为什么django使用ascii而不是utf-8?

时间:2016-04-03 18:55:26

标签: python django utf-8 ascii

在我的sqlite3数据库中以管理员身份添加数据(使用非ascii字符)时,出现以下错误:

Exception Type: UnicodeEncodeError at /admin/Project/vin/add/
Exception Value: 'ascii' codec can't encode character u'\xe2' in position 2:        
ordinal not in range(128)

我无法弄清楚是什么问题,因为它在所有不同的设置中都写了utf-8 ......并且ascii只出现在错误中。

我得到了解释

Django Version: 1.9.4
Python Version: 2.7.10
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'Project']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



> Traceback:

> File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-pac
> kages/django/core/handlers/base.py" in get_response
>   149.                     response = self.process_exception_by_middleware(e, request)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/core/handlers/base.py"
> in get_response
>   147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/contrib/admin/options.py"
> in wrapper
>   541.                 return self.admin_site.admin_view(view)(*args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/utils/decorators.py"
> in _wrapped_view
>   149.                     response = view_func(request, *args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/views/decorators/cache.py"
> in _wrapped_view_func
>   57.         response = view_func(request, *args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/contrib/admin/sites.py"
> in inner
>   244.             return view(request, *args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/contrib/admin/options.py"
> in add_view
>   1437.         return self.changeform_view(request, None, form_url, extra_context)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/utils/decorators.py"
> in _wrapper
>   67.             return bound_func(*args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/utils/decorators.py"
> in _wrapped_view
>   149.                     response = view_func(request, *args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/utils/decorators.py"
> in bound_func
>   63.                 return func.__get__(self, type(self))(*args2, **kwargs2)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/utils/decorators.py"
> in inner
>   184.                     return func(*args, **kwargs)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/contrib/admin/options.py"
> in changeform_view
>   1382.                     self.log_addition(request, new_object, change_message)
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/contrib/admin/options.py"
> in log_addition
>   714.             object_repr=force_text(object),
> 
> File
> "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages/django/utils/encoding.py"
> in force_text
>   80.                 s = six.text_type(bytes(s), encoding, errors)

vin模型

class Vin (models.Model):
    nom_vin =models.CharField (max_length = 20)
    millesime = models.IntegerField() 
    quantity = models.FloatField()
    appelation = models.ForeignKey(Appelation)
    def __str__(self):
        return self.nom_vin

2 个答案:

答案 0 :(得分:1)

尝试:

class Vin (models.Model):
    nom_vin =models.CharField (max_length = 20)
    millesime = models.IntegerField() 
    quantity = models.FloatField()
    appelation = models.ForeignKey(Appelation)
    def __unicode__(self):                        #You have __str__
        return self.nom_vin

答案 1 :(得分:1)

我几乎不接近理解Python中的编码规则,但在尝试解码此错误时,我更接近它。如果您只是想要正确的解决方案,请跳到最后(提示:python_2_unicode_compatible)。

根据Porting to Python 3,在Python 2 中,你可以同时拥有__str __()(必须返回字节字符串/对象(类型'str'))和__unicode __()(其中返回一个'unicode');但如果你只有一个就足够了:

  

print语句和str内置调用__str __()来确定对象的人类可读表示。 unicode内置调用__unicode __()(如果存在),否则返回__str __()并使用系统编码解码结果。相反,Model基类通过编码为UTF-8自动从__unicode __()派生__str __()。

另一方面,Python 3将unicode作为文字的默认值,只需要__str __(),提供一个unicode字符串,输入'str'(是的,与P2的字节字符串相同)。 Weeeeell,还有__bytes __(),但你可能永远都不需要它。

这一切都很好,花花公子,直到来自encoding.py及其force_text方法,管理界面使用:

def force_text(s, encoding='utf-8', strings_only=False, errors='strict'):
"""
Returns a text object representing 's' -- unicode on Python 2 and str on
Python 3. Treats bytestrings using the 'encoding' codec.
"""
[...]
try:
        if not issubclass(type(s), six.string_types):
            if six.PY3:
                if isinstance(s, bytes):
                    s = six.text_type(s, encoding, errors)
                else:
                    s = six.text_type(s)
            elif hasattr(s, '__unicode__'):
                s = six.text_type(s)
            else:
                s = six.text_type(bytes(s), encoding, errors)

错误在最后一行,我们只能用Python 2触发它(因为Python 3会触发if six.PY3),当没有__unicode__方法时,我们正在使用unicode_literals(编码.py)确实如此)bytes()(这只是str()的别名)传递一个unicode对象,当它需要一个字节时:

 $ python2
Python 2.7.11+ (default, Mar 30 2016, 21:00:42) 
# Python 2 uses bytes (type "str")  strings by default:
>>> bstr = 'â'
>>> type(bstr)
<type 'str'>
>>> bstr
'\xc3\xa2'
>>> bytes(bstr)
'\xc3\xa2'

# unicode_literals changes the default to unicode strings:
>>> from __future__ import unicode_literals
>>> ustr = 'â'
>>> type(ustr)
<type 'unicode'>
>>> ustr
u'\xe2'
# bytes() (str(), actually) expects a byte string, not unicode:
>>> bytes(ustr)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe2' in position 0: ordinal not in range(128) '
# We can encode ustr to bytes like so:
>>> bytes(ustr.encode('utf-8'))
'\xc3\xa2'
# Or with the equivalent b operator, for literals:
>>> bytes(b'â')
'\xc3\xa2'

# bstr has not changed:
>>> bytes(bstr)
'\xc3\xa2'

为了完整起见,Python 3的默认文字类型为unicode,但也称为'str'(字节字符串为'bytes'):

$ python3
Python 3.5.1+ (default, Jan 13 2016, 15:09:18) 
>>> ustr='á'
>>> ustr
'á'
>>> type(ustr)
<class 'str'>

>>> bstr='á'.encode('utf-8')
>>> bstr
b'\xc3\xa1'
>>> type(bstr)
<class 'bytes'>

# Note that you can't use `b` to enconde a non-ascii literal     
>>> bstr=b'á'
  File "<stdin>", line 1
SyntaxError: bytes can only contain ASCII literal characters.

现在,您似乎正在运行Python 2.7,但使用的是3.5库!不知道你是怎么做到这一点的,但是按照Volodymyr的建议,你已经使你的代码与Python 2兼容了,但是需要__str __()的Python 3打破了。

定义__str__和__unicode__以返回self.name,无论它们被转换为哪种类型似乎都适用于两者,但它必然会破坏某些时间,就像你遇到的那样,因为人们不打扰检查字符串类型(这是对我来说有点令人费解)。您可以使用__str__检查Python版本和字符串类型,并相应地传递或编码该值,但Django人员已经处理过:

Django适应的Python 2和3兼容性库 - Six(那是2 * 3,得到它吗?) - 提供python_2_unicode_compatible,一个类装饰器

  

将__str__方法别名为__unicode__并创建一个新的__str__   返回以UTF-8编码的__unicode __()的结果的方法。

这在本教程的第2部分中使用(docs.djangoproject.com/en/1.9/intro/tutorial02/#playing-with-the-api - 抱歉,无法建立更多链接):

from django.db import models
from django.utils.encoding import python_2_unicode_compatible

@python_2_unicode_compatible  # only if you need to support Python 2
class Question(models.Model):
    # ...
    def __str__(self):
        return self.question_text

呼。尽管如此,Ned Batchelder的实用Unicode(nedbatchelder.com/text/unipain.html),我想我已经开始了解它。不过,我可能会坚持使用Python 3 ...或PHP ...... ^ _ ^