使用 Django 和格式字符串的 UnicodeDecodeError
UnicodeDecodeError using Django and format-strings
我写了一个问题的小例子,让大家看看使用 Python 2.7 和 Django 1.10.8
是怎么回事
# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function
import time
from django import setup
setup()
from django.contrib.auth.models import Group
group = Group(name='schön')
print(type(repr(group)))
print(type(str(group)))
print(type(unicode(group)))
print(group)
print(repr(group))
print(str(group))
print(unicode(group))
time.sleep(1.0)
print('%s' % group)
print('%r' % group) # fails
print('%s' % [group]) # fails
print('%r' % [group]) # fails
退出并显示以下输出 + traceback
$ python .PyCharmCE2017.2/config/scratches/scratch.py
<type 'str'>
<type 'str'>
<type 'unicode'>
schön
<Group: schön>
schön
schön
schön
Traceback (most recent call last):
File "/home/srkunze/.PyCharmCE2017.2/config/scratches/scratch.py", line 22, in <module>
print('%r' % group) # fails
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 11: ordinal not in range(128)
有人知道这是怎么回事吗?
我很难找到解决您问题的通用方法。
__repr__()
是我理解的 return str,任何改变似乎会导致新问题的努力。
关于__repr__()
方法是在项目外定义的,可以重载方法。例如
def new_repr(self):
return 'My representation of self {}'.format(self.name)
Group.add_to_class("__repr__", new_repr)
我能找到的唯一可行的解决方案是明确告诉解释器如何处理字符串。
from __future__ import unicode_literals
from django.contrib.auth.models import Group
group = Group(name='schön')
print(type(repr(group)))
print(type(str(group)))
print(type(unicode(group)))
print(group)
print(repr(group))
print(str(group))
print(unicode(group))
print('%s' % group)
print('%r' % repr(group))
print('%s' % [str(group)])
print('%r' % [repr(group)])
# added
print('{}'.format([repr(group).decode("utf-8")]))
print('{}'.format([repr(group)]))
print('{}'.format(group))
在 python 2.x 中处理字符串是一团糟。
希望这能为如何解决(这是我能找到的唯一方法)问题带来一些启示。
这里的问题是您将 UTF-8 字节串插入到 Unicode 字符串中。您的 '%r'
字符串是一个 Unicode 字符串,因为您使用了 from __future__ import unicode_literals
,但是 repr(group)
(由 %r
占位符使用)returns 是一个字节串。对于 Django 模型,repr()
可以在表示中包含 Unicode 数据,使用 UTF-8 编码为字节串。这样的表示 不是 ASCII 安全的 。
对于您的具体示例,repr()
在您的 Group
实例上生成字节串 '<Group: sch\xc3\xb6n>'
。将其插入 Unicode 字符串会触发隐式解码:
>>> u'%s' % '<Group: sch\xc3\xb6n>'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 11: ordinal not in range(128)
请注意,我在 Python 会话中没有使用 from __future__ import unicode_literals
,因此 '<Group: sch\xc3\xb6n>'
字符串不是 unicode
对象,它是 str
字节串对象!
在Python2中,你应该避免混合使用Unicode和字节串。始终明确规范化您的数据(将 Unicode 编码为字节或将字节解码为 Unicode)。
如果您必须使用 from __future__ import unicode_literals
,您仍然可以使用 b
前缀创建字节串:
>>> from __future__ import unicode_literals
>>> type('') # empty unicode string
<type 'unicode'>
>>> type(b'') # empty bytestring, note the b prefix
<type 'str'>
>>> b'%s' % b'<Group: sch\xc3\xb6n>' # two bytestrings
'<Group: sch\xc3\xb6n>'
如果是这样,那么我们需要用我们自定义的方法覆盖 unicode 方法。试试下面的代码。它会起作用。我已经测试过了。
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from django.contrib.auth.models import Group
def custom_unicode(self):
return u"%s" % (self.name.encode('utf-8', 'ignore'))
Group.__unicode__ = custom_unicode
group = Group(name='schön')
# Tests
print(type(repr(group)))
print(type(str(group)))
print(type(unicode(group)))
print(group)
print(repr(group))
print(str(group))
print(unicode(group))
print('%s' % group)
print('%r' % group)
print('%s' % [group])
print('%r' % [group])
# output:
<type 'str'>
<type 'str'>
<type 'unicode'>
schön
<Group: schön>
schön
schön
schön
<Group: schön>
[<Group: schön>]
[<Group: schön>]
我对 Django 不熟悉。您的问题似乎是在 ASCI 中表示文本数据,而实际上是在 unicode 中。请尝试 Python.
中的 unidecode 模块
from unidecode import unidecode
#print(string) is replaced with
print(unidecode(string))
我认为真正的问题出在 django 代码中。
六年前的报道:
https://code.djangoproject.com/ticket/18063
我认为 django 的补丁可以解决它:
def __repr__(self):
return self.....encode('ascii', 'replace')
我认为 repr() 方法应该 return“7 位 ascii”。
我写了一个问题的小例子,让大家看看使用 Python 2.7 和 Django 1.10.8
是怎么回事# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, unicode_literals, print_function
import time
from django import setup
setup()
from django.contrib.auth.models import Group
group = Group(name='schön')
print(type(repr(group)))
print(type(str(group)))
print(type(unicode(group)))
print(group)
print(repr(group))
print(str(group))
print(unicode(group))
time.sleep(1.0)
print('%s' % group)
print('%r' % group) # fails
print('%s' % [group]) # fails
print('%r' % [group]) # fails
退出并显示以下输出 + traceback
$ python .PyCharmCE2017.2/config/scratches/scratch.py
<type 'str'>
<type 'str'>
<type 'unicode'>
schön
<Group: schön>
schön
schön
schön
Traceback (most recent call last):
File "/home/srkunze/.PyCharmCE2017.2/config/scratches/scratch.py", line 22, in <module>
print('%r' % group) # fails
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 11: ordinal not in range(128)
有人知道这是怎么回事吗?
我很难找到解决您问题的通用方法。
__repr__()
是我理解的 return str,任何改变似乎会导致新问题的努力。
关于__repr__()
方法是在项目外定义的,可以重载方法。例如
def new_repr(self):
return 'My representation of self {}'.format(self.name)
Group.add_to_class("__repr__", new_repr)
我能找到的唯一可行的解决方案是明确告诉解释器如何处理字符串。
from __future__ import unicode_literals
from django.contrib.auth.models import Group
group = Group(name='schön')
print(type(repr(group)))
print(type(str(group)))
print(type(unicode(group)))
print(group)
print(repr(group))
print(str(group))
print(unicode(group))
print('%s' % group)
print('%r' % repr(group))
print('%s' % [str(group)])
print('%r' % [repr(group)])
# added
print('{}'.format([repr(group).decode("utf-8")]))
print('{}'.format([repr(group)]))
print('{}'.format(group))
在 python 2.x 中处理字符串是一团糟。 希望这能为如何解决(这是我能找到的唯一方法)问题带来一些启示。
这里的问题是您将 UTF-8 字节串插入到 Unicode 字符串中。您的 '%r'
字符串是一个 Unicode 字符串,因为您使用了 from __future__ import unicode_literals
,但是 repr(group)
(由 %r
占位符使用)returns 是一个字节串。对于 Django 模型,repr()
可以在表示中包含 Unicode 数据,使用 UTF-8 编码为字节串。这样的表示 不是 ASCII 安全的 。
对于您的具体示例,repr()
在您的 Group
实例上生成字节串 '<Group: sch\xc3\xb6n>'
。将其插入 Unicode 字符串会触发隐式解码:
>>> u'%s' % '<Group: sch\xc3\xb6n>'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 11: ordinal not in range(128)
请注意,我在 Python 会话中没有使用 from __future__ import unicode_literals
,因此 '<Group: sch\xc3\xb6n>'
字符串不是 unicode
对象,它是 str
字节串对象!
在Python2中,你应该避免混合使用Unicode和字节串。始终明确规范化您的数据(将 Unicode 编码为字节或将字节解码为 Unicode)。
如果您必须使用 from __future__ import unicode_literals
,您仍然可以使用 b
前缀创建字节串:
>>> from __future__ import unicode_literals
>>> type('') # empty unicode string
<type 'unicode'>
>>> type(b'') # empty bytestring, note the b prefix
<type 'str'>
>>> b'%s' % b'<Group: sch\xc3\xb6n>' # two bytestrings
'<Group: sch\xc3\xb6n>'
如果是这样,那么我们需要用我们自定义的方法覆盖 unicode 方法。试试下面的代码。它会起作用。我已经测试过了。
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
from django.contrib.auth.models import Group
def custom_unicode(self):
return u"%s" % (self.name.encode('utf-8', 'ignore'))
Group.__unicode__ = custom_unicode
group = Group(name='schön')
# Tests
print(type(repr(group)))
print(type(str(group)))
print(type(unicode(group)))
print(group)
print(repr(group))
print(str(group))
print(unicode(group))
print('%s' % group)
print('%r' % group)
print('%s' % [group])
print('%r' % [group])
# output:
<type 'str'>
<type 'str'>
<type 'unicode'>
schön
<Group: schön>
schön
schön
schön
<Group: schön>
[<Group: schön>]
[<Group: schön>]
我对 Django 不熟悉。您的问题似乎是在 ASCI 中表示文本数据,而实际上是在 unicode 中。请尝试 Python.
中的 unidecode 模块from unidecode import unidecode
#print(string) is replaced with
print(unidecode(string))
我认为真正的问题出在 django 代码中。
六年前的报道:
https://code.djangoproject.com/ticket/18063
我认为 django 的补丁可以解决它:
def __repr__(self):
return self.....encode('ascii', 'replace')
我认为 repr() 方法应该 return“7 位 ascii”。