在 Django 管理员上传文件时出现 UnicodeEncodeError

在 Django 管理员上传文件时出现 UnicodeEncodeError

笔记:我在 StackOverflow 上问过这个问题,但我意识到这可能是提出此类问题的更合适地方。

我正在尝试通过 Django 管理应用程序上传名为“Testaråäö.txt”的文件。

我在 Debian 6 服务器上运行 Django 1.3.1、Gunicorn 0.13.4 和 Nginx 0.7.6.7。数据库是 PostgreSQL 8.4.9。其他 Unicode 数据可以毫无问题地保存到数据库中,所以我猜问题一定出在文件系统上。

我已经设置了

http {
    charset utf-8;
}

在我的 nginx.conf 中。LC_ALL 和 LANG 设置为“sv_SE.UTF-8”。运行“locale”可验证这一点。我甚至尝试在 nginx init 脚本中设置 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

更新locale.getpreferredencoding()sys.getfilesystemencoding()输出'UTF-8'locale.getdefaultlocale()输出('sv_SE', 'UTF8')。这对我来说似乎是正确的,所以我仍然不确定为什么我一直收到这些错误。

答案1

当我尝试上传包含非 ASCII 字符的文件名时,genericpath.py 出现了同样的问题,并给出了 UnicodeEncodeError。

我正在使用 nginx、uwsgi 和 django 以及 python 2.7。

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

以下是我采取的步骤 1. 添加到 /etc/nginx/nginx.conf(没有解决问题)

http {
    charset utf-8;
}
  1. 我将此行添加到 etc/default/locale(没有解决问题)

语言=“en_US.UTF-8”

  1. 我按照此处“成功”标题下列出的说明进行操作 https://code.djangoproject.com/wiki/ExpectedTestFailures (没有解决问题)

    aptitude install language-pack-en-base
    
  2. 发现此票 https://code.djangoproject.com/ticket/17816 建议在服务器上测试一下区域信息的情况

您认为

import locale
locales = "Current locale: %s %s -- Default locale: %s %s" % (locale.getlocale() + locale.getdefaultlocale())

在您的模板中

{{ locales }}

对我来说,问题是我的 Ubuntu 服务器上没有语言环境,也没有默认语言环境(尽管我在本地 OSX 开发机器上确实有它们),那么具有非 ASCII 文件名/路径的文件将无法正确上传,python 会引发 UnicodeEncodeError,但仅限于生产服务器。

解决方案

我将其添加到我的网站和网站管理员 uwsgi 配置文件中,例如 /etc/uwsgi-emperor/vassals/my-site-config-ini 文件

env = LANG=en_US.utf8

答案2

如果有人使用 mod_wsgi 来到这里使用 Apache,可以通过在站点配置文件的行中添加langlocale选项来解决这个问题。WSGIDaemonProcess

en_US.UTF-8通常应根据文档设置为:

https://modwsgi.readthedocs.io/en/develop/configuration-directives/WSGIDaemonProcess.html

就像这样:

lang=en_US.UTF-8 locale=en_US.UTF-8

例如:

WSGIDaemonProcess processName python-home=/path/to/venv python-path=/path/to/mydjangoproject lang=en_US.UTF-8 locale=en_US.UTF-8

添加这些选项后,重新启动 Apache,一切就绪了。

答案3

我遇到了同样的问题并且找到了适合我的情况的解决方法(我运行的是 Ubuntu)。

我在这里找到了一个很好的未回答的帖子,Karen 其中提供了一些有用的信息:

https://groups.google.com/forum/?fromgroups#!topic/django-users/hwNL7i6IeIY

这让我想到了这一点:

https://code.djangoproject.com/wiki/ExpectedTestFailures

我为 Ubuntu 安装了缺少的“语言包”。并以 root 身份在 shell 中运行:

locale-gen en_US.UTF-8

并且现在正在工作。

看起来,在 Python 的低层中,一些调用 Glibc 的东西需要由 locale-gen 生成的一些编译文件才能正常工作。

我看过了http://packages.debian.orgDebian 中没有这样的软件包。

尝试运行以下命令并重新启动守护程序,然后重试:

locale-gen sv_SE.UTF-8

或者安装任何 Debian 特定的区域设置/语言包(如果有)。

相关内容