Znaki diakrytyczne w plikach uploadowanych przez Django i Apache’a

Django na ogół znakomicie radzi sobie z obsługą znaków diakrytycznych i możemy śmiało używać ogonków w aplikacjach pisanych za pomocą tego frameworka. Możemy jednak natknąć się na problem, jeżeli spróbujemy za pomocą formularza wysłać na serwer plik z nazwą zawierającą nasze ogonki:

Exception Type:   UnicodeEncodeError
Exception Value:  'ascii' codec can't encode characters in position 46-49: ordinal not in range(128)

Błąd leży tu jednak nie po stronie Django, a Apache’a, o czym piszą twórcy frameworka:

If you get a UnicodeEncodeError
=============================== 

If you're taking advantage of the internationalization features of Django (see
:ref:`topics-i18n`) and you intend to allow users to upload files, you must
ensure that the environment used to start Apache is configured to accept
non-ASCII file names. If your environment is not correctly configured, you
will trigger ``UnicodeEncodeError`` exceptions when calling functions like
``os.path()`` on filenames that contain non-ASCII characters. 

To avoid these problems, the environment used to start Apache should contain
settings analogous to the following:: 

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8' 

Consult the documentation for your operating system for the appropriate syntax
and location to put these configuration items; ``/etc/apache2/envvars`` is a
common location on Unix platforms. Once you have added these statements
to your environment, restart Apache.

Dopisujem zatem do /etc/apache2/envvars:

export LANG='en_US.UTF-8'
export LC_ALL='en_US.UTF-8'

Ewentualnie możemy wyedytować zmienną ENV w pliku /etc/init.d/apache2 (oczywiście, jest to mniej eleganckie rozwiązanie), np.:

ENV="env -i LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 PATH=/usr/local/bin:/usr/bin:/bin"

Teraz Apache powinien uruchamiać się ze zmiennymi środowiskowymi, które nakażą mu korzystanie z Unicodu. Okazuje się jednak, że to nie koniec przygód, bo, zwracając plik użytkownikowi, otrzymamy:

Exception Type:   UnicodeEncodeError
Exception Value:  'ascii' codec can't encode characters in position 23-26: ordinal not in range(128), HTTP response headers must be in US-ASCII format

Okazuje się, że nagłówek HTTP nie może zostać prawidłowo zakodowany. Musimy więc pomóc Django, jawnie kodując nazwę pliku w obiekcie HttpResponse za pomocą metody encode(). Tym samym zamiast:

response = HttpResponse(open(path), mimetype='%s' % (mimetypes.guess_type(path)[0]))
response['Content-Disposition'] = 'attachment; filename=%s' % (myfile.filename())

powinniśmy użyć:

response = HttpResponse(open(path), mimetype='%s' % (mimetypes.guess_type(path)[0]))
response['Content-Disposition'] = 'attachment; filename="%s"' % (myfile.filename().encode('utf-8'))

Dodawanie komentarzy

XHTML: Możesz używać tagów: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">