Django 图片上传无法上传日语命名的图片

3

当我上传日语命名的图像时,出现以下错误:ascii' codec can't encode characters in position 45-48: ordinal not in range(128)

使用英文字符命名的图像上传完美无缺。此外,奇怪的是,我遇到的错误只发生在将其上传到服务器时。日语命名的图像在开发中可以正常工作,但在部署服务器上无法上传。

我的模型:

class Tenant_Post(models.Model):
    user = models.ForeignKey(User,on_delete=models.CASCADE,null=True)
    name = models.CharField(max_length=255,null=True)
    image = models.FileField(upload_to='image/tenant/',null=True)
    posted_on = models.DateTimeField(auto_now_add=True, auto_now=False)
    last_modified_on = models.DateTimeField(auto_now_add=False, 
    auto_now=True)

    def __unicode__(self):
        return self.name

我的观点:
@login_required(login_url='/')
def new(request):
    if request.method == 'POST':
        print request.POST
        form = TenantForm(request.POST or None, request.FILES or None)
        if form.is_valid():
            instance = form.save(commit=False)
            instance.user = request.user
            instance.save()
            print 'success'
            return HttpResponseRedirect(reverse('tenant:all'))
        else:
            print 'fail'
            return render(request,'tenant/new.html',{'form':form,})
    else:
        form = TenantForm()
        return render(request,'tenant/new.html',{'form':form,})

完整的追踪信息如下:

File "/opt/python/run/venv/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  41.             response = get_response(request)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)

File "/opt/python/current/app/tenant/views.py" in edit
  64.                 instance.save()

File "/opt/python/run/venv/lib/python2.7/site-packages/django/db/models/base.py" in save
  806.                        force_update=force_update, update_fields=update_fields)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/db/models/base.py" in save_base
  836.             updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/db/models/base.py" in _save_table
  900.                       for f in non_pks]

File "/opt/python/run/venv/lib/python2.7/site-packages/django/db/models/fields/files.py" in pre_save
  296.             file.save(file.name, file.file, save=False)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/db/models/fields/files.py" in save
  94.         self.name = self.storage.save(name, content, max_length=self.field.max_length)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/core/files/storage.py" in save
  53.         name = self.get_available_name(name, max_length=max_length)

File "/opt/python/run/venv/lib/python2.7/site-packages/django/core/files/storage.py" in get_available_name
  77.         while self.exists(name) or (max_length and len(name) > max_length):

File "/opt/python/run/venv/lib/python2.7/site-packages/django/core/files/storage.py" in exists
  392.         return os.path.exists(self.path(name))

File "/opt/python/run/baselinenv/lib64/python2.7/genericpath.py" in exists
  26.         os.stat(path)

Exception Type: UnicodeEncodeError at /tenant/edit/4/
Exception Value: 'ascii' codec can't encode characters in position 45-48: ordinal not in range(128)

ASCII 无法保存日语名称,请尝试重命名或更改编码。 - Vladyslav
我不被允许更改名称,你能告诉我更多关于改变编码的事吗? - Ash Singh
https://dev59.com/upXfa4cB1Zd3GeqPdlvv - Vladyslav
你的 Django 设置使用了哪种编码方式,文件系统又使用了哪种编码方式?还有,请完整地贴出 traceback(追踪回溯)信息。 - bruno desthuilliers
@Vladyslav,你提供的关于二进制数据base64编码的问题链接完全不相关 - 我们在谈论字符串编码(ascii,utf8等...)。 - bruno desthuilliers
显示剩余7条评论
3个回答

5

我还没有测试过日语,但是它可以处理其他一些带有特殊字符的语言,例如葡萄牙语:

在您的settings.py文件中添加以下内容:

DEFAULT_FILE_STORAGE = 'app.models.ASCIIFileSystemStorage'

你的app.models.ASCIIFileSystemStorage

# This Python file uses the following encoding: utf-8
from django.db import models
from django.core.files.storage import FileSystemStorage
import unicodedata

class ASCIIFileSystemStorage(FileSystemStorage):
    """
    Convert unicode characters in name to ASCII characters.
    """
    def get_valid_name(self, name):
        name = unicodedata.normalize('NFKD', name).encode('ascii', 'ignore')
        return super(ASCIIFileSystemStorage, self).get_valid_name(name)

它可以工作,但文件名已更改,我想知道是否有一种方法可以保留文件本身的原始名称? - Mohamed Abd El-hameed

2
你的错误是由os.stat(path)调用引起的,这意味着你的文件系统不支持日语字符(实际上它可能只支持ascii、某些拉丁-xxx或windows-yyy编码)。
在这里,你主要有两个解决方案:要么配置你的系统在任何地方都使用utf-8(这在我看来是一个明智的选择),要么确保你只使用你的系统编码(或者只使用纯ascii)来命名文件系统等(参见leeaandroo的答案)。

它运行得很好,但我仍然想知道如何配置我的系统以在所有地方使用UTF-8。我在AWS EC2上部署时遇到了这个问题,而不是在我的开发环境中。 - Ash Singh
抱歉,我无法帮助您处理AWS相关问题。 - bruno desthuilliers

-1

添加编码为 utf-8,这样就可以接受大多数语言了。同时,在模板 HTML 中使用字符集 utf-8。

# -*- coding: UTF-8 -*- in at the top the file

<meta charset="utf-8"/> in html templates

编辑: 请阅读官方文档或添加此行

 from __future__ import unicode_literals

https://docs.djangoproject.com/en/1.11/ref/unicode/


第一个定义模块中的文字串编码,第二个告诉浏览器把内容解释为utf-8编码,但在这里完全无关紧要(不会修复系统编码),如果你的内容不是utf-8编码,甚至会有害。此外,Django通过适当的响应头知道如何指定有效编码(在项目设置文件中使用的编码),因此在Django项目中它是完全无用的。 - bruno desthuilliers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接