【问题标题】:UnicodeEncodeError when uploading files in Django admin在 Django admin 中上传文件时出现 UnicodeEncodeError
【发布时间】:2012-03-01 19:14:58
【问题描述】:

我的问题与报告的here 类似,但建议的解决方案对我不起作用。我正在尝试通过 Django 管理应用上传一个名为“Testaråäö.txt”的文件。

我在 Debian 6 服务器上运行带有 Gunicorn 0.13.4 和 Nginx 0.7.6.7 的 Django 1.3.1。数据库是 PostgreSQL 8.4.9。其他 Unicode 数据保存到数据库没有问题,所以我猜问题一定是文件系统的问题。

我已经设置了

http {
    charset utf-8;
}

在我的 nginx.conf 中。 LC_ALL 和 LANG 设置为 'sv_SE.UTF-8'。运行 'locale' 可以验证这一点。我什至尝试在我的 nginx 初始化脚本中设置 LC_ALL 和 LANG,以确保正确设置语言环境。

这是回溯:

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 的原始响应标头,如果有意义的话:

独角兽:

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

【问题讨论】:

  • 你有没有解决这个问题?你是怎么开始gunicorn的?
  • 对不起,没有。我告诉我的客户在找到解决方案之前避免使用 unicode 字符(这越来越像迁移到不同的服务器)。我正在使用 Supervisor 启动 gunicorn。
  • 这也发生在我们身上。相同的设置 - NginX、Supervisor、Gunicorn 运行 Django 应用程序。我浪费了两个小时试图修复它,在互联网上到处尝试了所有建议,但没有任何运气。希望有人最终会找到一种方法来完成这项工作。

标签: django file-upload unicode nginx gunicorn


【解决方案1】:

运行 django 服务的服务似乎是一个常见问题,无论是 apache、gunicorn + supervisor、daemontools 等......并不总是使用正确的环境变量。

在这种情况下,gunicorn 是由 supervisor 启动的,所以你必须通过 environment 选项明确告诉 supervisor 使用 utf-8:

environment=LANG=en_US.UTF-8, LC_ALL=en_US.UTF-8, LC_LANG=en_US.UTF-8

【讨论】:

  • 在 Supervisor 3.0a8(Debian Squeeze 中提供的版本)中,environment 选项必须在配置文件的 [supervisord] 部分中全局指定。 [program:*] 部分无法识别它。
  • 如果您运行的是 Apache,我通过编辑 /etc/apache2/envvars、取消注释以使用系统默认语言环境、然后停止并启动 Apache 来解决此问题。
【解决方案2】:

在尝试上传包含非 ASCII 字符的文件名时,我遇到了 genericpath.py 给出 UnicodeEncodeError 的相同问题。

我在 python 2.7 中使用 nginx、uwsgi 和 django。

在本地一切正常,但在服务器上却不行

这是我采取的步骤:

  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 这建议测试服务器上的视图以了解区域设置信息发生的情况

Django 视图

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

更新

转到 docker 后,我又开始遇到同样的错误。 在进一步研究之后,我意识到在上面的 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 dockerfile 中

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,你可以在 shell 中运行它

$ export LANG=en_US.UTF-8

然后运行上面的 RUN 命令(但没有 RUN)。

参考资料:

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

【讨论】:

  • 这是一个很好的答案,带有分步诊断指南。我不知道为什么它的赞成票这么少。请注意,在 Ubuntu 的情况下,您需要您的语言的语言包。因此,如果将LANG env 设置为西班牙语,则需要aptitude install language-pack-es-base。所有其他语言都类似。
  • 需要 Fedora OCI 映像:``` RUN ["dnf", "install", "-y", "glibc-locale-source", "glibc-langpack-en"] ENV LANG= en_US.utf8 运行 localedef --quiet --force -i en_US -f UTF-8 en_US.UTF-8 ``
猜你喜欢
  • 2016-04-10
  • 1970-01-01
  • 1970-01-01
  • 2010-11-15
  • 2011-03-09
  • 2011-05-22
  • 1970-01-01
  • 2011-08-14
  • 2017-05-22
相关资源
最近更新 更多