UnicodeEncodeError при загрузке файлов в админке Django - PullRequest
8 голосов
/ 09 февраля 2012

Мой вопрос похож на тот, о котором сообщалось здесь , но предложенное решение не работает для меня. Я пытаюсь загрузить файл с именем «Testaråäö.txt» через приложение администратора Django.

Я использую Django 1.3.1 с Gunicorn 0.13.4 и Nginx 0.7.6.7 на сервере Debian 6. База данных PostgreSQL 8.4.9. Другие данные Unicode без проблем сохраняются в базе данных, поэтому я думаю, что проблема должна быть связана с файловой системой.

Я установил

http {
    charset utf-8;
}

в моем nginx.conf. LC_ALL и LANG установлены в «sv_SE.UTF-8». Запуск 'locale' подтверждает это. Я даже пытался установить LC_ALL и LANG в моем скрипте инициализации nginx, просто чтобы убедиться, что локаль установлена ​​правильно.

Вот трассировка:

Traceback (most recent call last):

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/core/handlers/base.py", line 111, in get_response
response = callback(request, *callback_args, **callback_kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/contrib/admin/options.py", line 307, in wrapper
return self.admin_site.admin_view(view)(*args, **kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/utils/decorators.py", line 93, in _wrapped_view
response = view_func(request, *args, **kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/views/decorators/cache.py", line 79, in _wrapped_view_func
response = view_func(request, *args, **kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 197, in inner
return view(request, *args, **kwargs)

File "/srv/django/letebo/app/cms/admin.py", line 81, in change_view
return super(PageAdmin, self).change_view(request, obj_id)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/utils/decorators.py", line 28, in _wrapper
return bound_func(*args, **kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/utils/decorators.py", line 93, in _wrapped_view
response = view_func(request, *args, **kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/utils/decorators.py", line 24, in bound_func
return func(self, *args2, **kwargs2)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/db/transaction.py", line 217, in inner
res = func(*args, **kwargs)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/contrib/admin/options.py", line 985, in change_view
self.save_formset(request, form, formset, change=True)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/contrib/admin/options.py", line 677, in save_formset
formset.save()

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/forms/models.py", line 482, in save
return self.save_existing_objects(commit) + self.save_new_objects(commit)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/forms/models.py", line 613, in save_new_objects
self.new_objects.append(self.save_new(form, commit=commit))

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/forms/models.py", line 717, in save_new
obj.save()

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/db/models/base.py", line 460, in save
self.save_base(using=using, force_insert=force_insert, force_update=force_update)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/db/models/base.py", line 504, in save_base
self.save_base(cls=parent, origin=org, using=using)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/db/models/base.py", line 543, in save_base
for f in meta.local_fields if not isinstance(f, AutoField)]

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/db/models/fields/files.py", line 255, in pre_save
file.save(file.name, file, save=False)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/db/models/fields/files.py", line 92, in save
self.name = self.storage.save(name, content)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/core/files/storage.py", line 48, in save
name = self.get_available_name(name)

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/core/files/storage.py", line 74, in get_available_name
while self.exists(name):

File "/srv/.virtualenvs/letebo/lib/python2.6/site-packages/django/core/files/storage.py", line 218, in exists
return os.path.exists(self.path(name))

File "/srv/.virtualenvs/letebo/lib/python2.6/genericpath.py", line 18, in exists
st = os.stat(path)

UnicodeEncodeError: 'ascii' codec can't encode characters in position 52-54: ordinal not in range(128)

ОБНОВЛЕНИЕ: Я попытался запустить Gunicorn с включенной отладкой, и файл загружался без каких-либо проблем. Я полагаю, это должно означать, что проблема связана с Nginx. Все же бьет меня, где искать, хотя. Вот необработанные заголовки ответа от Gunicorn и Nginx, если это имеет смысл:

Gunicorn:

HTTP/1.1 302 FOUND
Server: gunicorn/0.13.4
Date: Thu, 09 Feb 2012 14:50:27 GMT
Connection: close
Transfer-Encoding: chunked
Expires: Thu, 09 Feb 2012 14:50:27 GMT
Vary: Cookie
Last-Modified: Thu, 09 Feb 2012 14:50:27 GMT
Location: http://my-server.se:8000/admin/cms/page/15/
Cache-Control: max-age=0
Content-Type: text/html; charset=utf-8
Set-Cookie: messages="yada yada yada"; Path=/

Nginx:

HTTP/1.1 500 INTERNAL SERVER ERROR
Server: nginx/0.7.67
Date: Thu, 09 Feb 2012 14:50:57 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: close
Vary: Cookie

500

Ответы [ 2 ]

9 голосов
/ 07 мая 2012

Кажется, что общая проблема заключается в том, что служба, которая запускает службу django, будь то apache, gunicorn + supervisor, daemontools и т. Д. ... не всегда использует правильные переменные среды.

В этом случае gunicorn запускается супервизором, поэтому вы должны явно указать супервизору использовать utf-8 с помощью параметра среды:

environment=LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF-8
3 голосов
/ 23 июня 2015

У меня была такая же проблема с genericpath.py, выдающим UnicodeEncodeError при попытке загрузить имя файла без символов ASCII.

Я использовал nginx, uwsgi и django с python 2.7.

Все работало нормально локально, но не на сервере

Вот шаги, которые я предпринял:

  1. добавлено в /etc/nginx/nginx.conf (не устранило проблему)

    http {
         charset utf-8;
    }
    
  2. Я добавил эту строку в etc / default / locale (проблема не была устранена)

    LANGUAGE="en_US.UTF-8"
    
  3. Я следовал инструкциям, приведенным здесь под заголовком «Успех» https://code.djangoproject.com/wiki/ExpectedTestFailures (не устранил проблему)

    aptitude install language-pack-en-base
    
  4. Найден через этот билет https://code.djangoproject.com/ticket/17816 который предложил проверить представление на сервере, что происходит с информацией о локали

Вид Джанго

import locale

def locales(request):
    """Display the locales"""
    locales = "Current locale: %s %s -- Default locale: %s %s" % (
        locale.getlocale() + locale.getdefaultlocale())
    default_encoding =  sys.getdefaultencoding()
    file_system_encoding = sys.getfilesystemencoding()

    context = {
        'locales': locales,
        'default_encoding': default_encoding,
        'file_system_encoding': file_system_encoding,  # affects file uploads
    }
    return render(request, 'testing/locales.html', context)

Шаблон Django

<h2>Locales</h2>
<p>{{ locales }}</p>

<h2>Default Encoding</h2>
<p>{{ default_encoding }}</p>

<h2>File System Encoding</h2>
<p>{{ file_system_encoding }}</p>

Для меня проблема заключалась в том, что у меня не было локали и локали по умолчанию на моем сервере Ubuntu (хотя они были на моей локальной машине с OSX), тогда файлы с именами / путями, отличными от ASCII, не будут корректно загружаться с python вызов UnicodeEncodeError, но только на рабочем сервере.

Решение

Я добавил это как в конфигурационный файл uwsgi моего сайта, так и в мой админ сайта. например Файл / etc / uwsgi-emperor / vassals / my-site-config-ini

env = LANG=en_US.utf8

Обновление

После перехода в докер я снова начал получать ту же ошибку. После более подробного изучения я понял, что в экземпляре uwsgi django import sys; sys.getfilesystemencoding() или {{ file_system_encoding }} выше возвращался ANSI_X3.4-1968, однако, если бы я запустил свой собственный экземпляр python и запустил import sys; sys.getfilesystemencoding(), я бы получил UTF-8. Формат ANSI_X3.4-1968 - это то, что вызывает UnicodeEncodeError.

Таким образом, в дополнение к решению uwsgi, указанному в этом ответе выше, мне также пришлось добавить это в мой докер-файл Django

ENV LANG en_US.UTF-8
RUN apt-get update && install -y locales && \
    sed -i -e "s/# $LANG.*/$LANG UTF-8/" /etc/locale.gen && \
    locale-gen --purge &&\
    update-locale LANG=$LANG

Или, если вы не используете Docker, вы можете просто запустить это в оболочке

$ export LANG=en_US.UTF-8

Затем выполните указанную выше команду RUN (но без RUN).

Ссылки:

http://stackoverflow.com/a/37246853/3003438
https://docs.djangoproject.com/en/dev/howto/deployment/wsgi/uwsgi/
...