Uploaded django image ends up with wrong filename - django

I don't know if this is expected behavior or not, but if I create a project with a single model with an ImageField field and upload a photo with the filename "árvórés", the uploaded file is saved with an incomprehensible filename(ascii, I presume). As a direct result, that photo becomes impossible to retrieve from the site.
Is this normal? If yes, then how to allow those types of filenames?

The issue is that you haven't specified how the POST data should be encoded by the browser, and subsequently you are getting whatever the browser has guessed it should use - usually ISO-8859-1 instead of Unicode (UTF-8).
The HTML 4.01 spec for the FORM element includes the "accept-charset" attribute which allows you to specify your preference for which encoding to POST data with:
accept-charset = charset list [CI]
This attribute specifies the list of
character encodings for input data
that is accepted by the server
processing this form. The value is a
space- and/or comma-delimited list of
charset values. The client must
interpret this list as an exclusive-or
list, i.e., the server is able to
accept any single character encoding
per entity received.
The default value for this attribute
is the reserved string "UNKNOWN". User
agents may interpret this value as the
character encoding that was used to
transmit the document containing this
FORM element.
In other words, if you serve a page encoded in UTF-8, the browser would default to posting requests in UTF-8.
The best fix is to specify the character encoding for all your pages by either including the appropriate encoding in your response headers, or including something like the following in your HTML within the HEAD section:
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
The HTML 4.01 spec has a section on how to specify which character encoding you are serving.
An alternate but lesser fix is to not specify the character encoding anywhere, and instead decode your filename manually assuming the browser is sending in the default encoding of ISO-8859-1:
def upload_file(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
filename = form.cleaned_data.image.name.decode('iso-8859-1')
...

Related

PDFBox can't create Form if fields contain non-latin character

I'm trying to create PDF from ColdFusion10 using Apache PDFBox lib.
I have a template PDF file with form fields and filling them out with user data.
But if user inputs non-latin character in any form field I got exception.
For example: Turkish language has character 'İ' (capital i with dot) so I got message:
U+0131 is not available in this font's encoding: WinAnsiEncoding.
Form fıelds in the pdf template use 'Arial' font. Should I use any specific font embed to PDF template to make all characters work? Or it depends on what fonts installed on server (Linux)?
Any help very appreciated!

Django: Send posted files to a different form

Well, I have to send files posted by one form to other form, I have to read an XML file first, if the file is valid I'll redirect to the next form, which has to have the valid file received in the past form. I tried with sessions but I'm not sure if it's the right way to go, here my models.
class InitialForm(models.Model):
...
name = models.CharField(max_length=50)
xml = models.FieldField(label='Please choose an XML file')
...
class SecondForm(models.Model):
...
name = models.CharField(max_length=50)
pdf = models.FieldField(label='Please choose a PDF file')
...
The reason I got two forms is because I've got to read the XML first and validate it, and then in the next form 'SecondForm' show the data I just parse from the XML in order to verify and give feedback to the user. Then both files must be inserted in a database, only if the first one is valid.
Any help will be welcome.
Thanks in advance.
I think what you need is a form wizard that Django offers for situations when you need to build a form that is split into multiple requests.
From their docs this is how it works:
The user visits the first page of the wizard, fills in the form and
submits it.
The server validates the data. If it’s invalid, the form
is displayed again, with error messages. If it’s valid, the server
saves the current state of the wizard in the backend and redirects to
the next step.
Step 1 and 2 repeat, for every subsequent form in the
wizard.
Once the user has submitted all the forms and all the data has
been validated, the wizard processes the data – saving it to the
database, sending an email, or whatever the application needs to do.

Django1.4: Generic way to set language links in template to work with i18n_patterns?

I started to play with new i18n_patterns in Django 1.4. Basically, i want to have language links for each of my supported languages on all of my templates headers. I have implemented my header as a separate template that is being included in other templates.
Is there a way to keep my header generic and solve this without passing the current view name or current url in template context? I guess it comes to a question how do i retrieve the current view or url from inside the template in a generic way.
BTW, i discovered that my previous approach with set_lang view to change the active language using the referrer will be broken with url_patterns as after changing the language it will change it back when redirected to the referred view.
Any help figuring out the common approach to set language links in templates to be used with url_patterns in a generic way would be appreciated!
Basically, there are two different approaches to setting the language. You can use i18n_patterns to auto-magically prefix your urls with a language code, or you can use the django.views.i18n.set_language view to change the value of the language code in the user's session (or a cookie, if your project doesn't have session support).
It's worth noting the algorithm LocaleMiddleware uses to determine language:
First, it looks for the language prefix in the requested URL. This is only performed when you are using the i18n_patterns function in your root URLconf. See Internationalization: in URL patterns for more information about the language prefix and how to internationalize URL patterns.
Failing that, it looks for a django_language key in the current user's session.
Failing that, it looks for a cookie.The name of the cookie used is set by the LANGUAGE_COOKIE_NAME setting. (The default name is django_language.)
Failing that, it looks at the Accept-Language HTTP header. This header is sent by your browser and tells the server which language(s) you prefer, in order by priority. Django tries each language in the header until it finds one with available translations.
Failing that, it uses the global LANGUAGE_CODE setting.
The problem you're likely running into is that you can't use set_language to redirect from a url that's already being served with a language prefix, unless you specifically pass a next parameter in the POST data. This is because set_language will default to redirecting to the referrer, which will include the previous language prefix, which LocaleMiddleware will then see and serve the content in the old language (because it looks for a language prefix in the url before checking the django_language session variable).
An example, for clarity:
Your user is on /en/news/article/1000, and clicks on the link which will post 'language=es' to set_language.
set_language sees 'language=es', checks to see if 'es' is available, and then sets the 'django_language' session variable (or cookie) to 'es'
Since you haven't set 'next', it redirects to the value of reqeuest.META['HTTP_REFERRER'], which is /en/news/article/1000
LocaleMiddleware (source) sees the 'en' prefix in the url, and activates the 'en' language and sets request.LANGUAGE_CODE to 'en'
I see two possible solutions:
Write your own set_language view (see the original source here), which will check for a language prefix in the referrer(use django.utils.translation.get_language_from_path), and change it to the prefix for the newly selected language before redirecting back to it.
Use javascript to do the same operation client-side, and set the next POST parameter. Really this is kind of silly; it would probably be simpler to just use javascript to dynamically prepend all urls with the user's preferred language code, and forget about set_language altogether.
It seems that this new set_language view should probably be Django's default behavior. There was a ticket raised, which included a proposed implementation, but didn't really describe the problem and was subsequently closed. I suggest opening a new ticket with a better description of your use case, the problem caused by the existing set_language implementation, and your proposed solution.
Actually, there's no need to fiddle with your view. Django has a handy slice tag, so you can just use {{ request.path|slice:'3:' }} as your link URL. This lops the language code prefix off so the language is set by the set_lang function.
Having had the same problem today with Django 1.7, I devised this solution - not very DRY but it seems to work OK (and all my tests are passing, so...).
Rather than using the builtin set_language view, I copied it and made one tiny adjustment - here's the result:
def set_language(request):
"""
Redirect to a given url while setting the chosen language in the
session or cookie. The url and the language code need to be
specified in the request parameters.
Since this view changes how the user will see the rest of the site, it must
only be accessed as a POST request. If called as a GET request, it will
redirect to the page in the request (the 'next' parameter) without changing
any state.
"""
next = request.POST.get('next', request.GET.get('next'))
if not is_safe_url(url=next, host=request.get_host()):
next = request.META.get('HTTP_REFERER')
if not is_safe_url(url=next, host=request.get_host()):
next = '/'
lang_code = request.POST.get('language', None)
# Start changed part
next = urlparse(next).path # Failsafe when next is take from HTTP_REFERER
# We need to be able to filter out the language prefix from the next URL
current_language = translation.get_language_from_path(next)
translation.activate(current_language)
next_data = resolve(next)
translation.activate(lang_code) # this should ensure we get the right URL for the next page
next = reverse(next_data.view_name, args=next_data.args, kwargs=next_data.kwargs)
# End changed part
response = http.HttpResponseRedirect(next)
if request.method == 'POST':
if lang_code and check_for_language(lang_code):
if hasattr(request, 'session'):
request.session[LANGUAGE_SESSION_KEY] = lang_code
else:
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, lang_code,
max_age=settings.LANGUAGE_COOKIE_AGE,
path=settings.LANGUAGE_COOKIE_PATH,
domain=settings.LANGUAGE_COOKIE_DOMAIN)
return response
To sum it up, I resolve() the view parameters for next, then pass the data to reverse() after activating the new language. Hope this helps.
My apologies for the long delay. Thank you all for your answers.
First of all to comment on the two solution options by Chris:
Neither custom set_language nor javascript are good for the purpose as the whole beauty of url patterns is being SEO friendly.
Furthermore, simply replacing the prefix language in URL cannot be treated as full solution for urlpattern based urls as the whole URL might be translatable too. Ex: /en/profile/ for english and /fr/profil/ for french.
To solve such a problem one needs to capture the viewfunc and the arguments in order to reverse it for different language.
Fortunately for me, my project does not use translatable URLs for now and I took the following approach.
Add django.core.context_processors.request to TEMPLATE_CONTEXT_PROCESSORS so that request to be available in template rendering context.
Use RequestContext in views when rendering your views. This is always the case for me independent of the topic.
Write a quite simple templatetag that requires the context and takes an argument a language code to return the current URL in the given language. It basically makes sure the current URL has valid language-code prefix and simply returns another string that is the same current URL with replaced language-code.
ex:
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def get_current_url_for_lang(context, lang_code):
request=context.get('request',False)
if not request:
return None
request=context['request']
curr_url=request.path
if len(curr_url) < 4 or curr_url[0] != '/' or curr_url[3] != '/':
return curr_url
if context.get('LANGUAGES',False):
codes = []
for code,name in context['LANGUAGES']:
codes.append(code)
curr_langcode = curr_url[1:3]
if lang_code not in codes or curr_langcode not in codes:
return curr_url
changed_url = '/'+lang_code+curr_url[3:]
return changed_url
Furthermore, if one does not like to inject full request into context it will be quite straightforward to write your own context_processor that simply pushes the request.path as current_url_path for instance and use that instead in your templatetag.
Your comments are welcomed as always!

Attaching a .png file to an email sent by satchmo

In a Satchmo Store, I need to attach a small .png (a barcode) to an email that django sends on completion of the order. The email is formatted in HTML using send_order_confirmation() which calls send_store_mail() (both part of satchmo.) Neither of these functions offer the ability to attach a file (I think) so should I just re-write them? I was wondering if it is possible/better to do this using signals. Maybe rendering_store_mail() ?
By the way, the barcode would be dynamically generated, so there's no way of having a link to a file on a server somewhere.
Many thanks,
Thomas
well I too had to add extra infos to the confirmation emails, only text though. So this would be the very easy way to add extra-stuff to emails using signals, which IMHO, is the best approach to do it. Always use signals if you can avoid overriding the satchmo-core ;-)
define your listener to add some context for the rendering. In this case I'm adding the contents of an extra notes field, and the barcode for this order, supposing there is a function named get_barcode_img(<order>), to the context. I'm supposing here too, that the get_barcode_img function would return not just a png, but something like a MIMEImage (like from email.MIMEImage import MIMEImage) to be able to just include it inline. Also, there might be more infos needed, like a MIME-header for the img.
# localsite/payment/listeners.py
def add_extra_context_to_store_mail(sender,
send_mail_args={}, context={}, **kwargs):
if not 'order' in context:
return
context['barcode_header'] = get_barcode_header(context['order'])
context['barcode_img'] = get_barcode_img(context['order'])
context['notes'] = context['order'].notes
connect the listener to the signal somewhere where the code will be "discovered" for sure, like models.py:
# localsite/payment/models.py
from satchmo_store.shop.signals import rendering_store_mail, order_notice_sender
rendering_store_mail.connect(payment_listeners.add_extra_context_to_store_mail, sender=order_notice_sender)
override the templates locally (e.g. order_placed_notice.html) to add the new context. Be aware where you put your templates, as the path is essential for django to take your new template instead of the satchmo's one. In this case, starting from your project's root-path, there could be a templates-folder and inside it, there must be exactly the same path as in the satchmo-folder. E.g. /templates/shop/email/order_placed_notice.html ... this can be applied for any "valid" templates-folder inside an app. It's up to you to decide, where/how the templates should be organized.
<!-- templates/shop/email/order_placed_notice.html -->
<!DOCTYPE ...><html>
<head>
<!-- include the image-header here somewhere??? -->
<title></title>
</head>
<body>
...
Your comments:
{{ notes }}
Barcode:
{{ barcode_img }}"

Django multilanguage support

Using django if a text is stored in French or Hindi.How will this be stored and retrieved in a text box field
Models.py
class Details(models.Model):
title = models.CharField(max_length = 255)
html page:
<form action="/pjt/details">
<input type="text" name="nee_n"id="neen_n" />
</form>
How to store this in the db and retieve back the same .Is there any setting to be changed in settings.py
Thanks..
Django is based on Unicode and so the language characters will be stored correctly.
Storing the language, i.e. the user's culture is a different issue. This can be initially gleaned from the HTTP request in the format 'en_US' or 'fr_FR'.
This standard is a concatenation of ISO 639-1 and ISO 3166-1.
However the browser culture cannot always be relied upon and so the interface should give the user the opportuinity to change their culture.