使用 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>]

参考:https://docs.python.org/2/howto/unicode.html

我对 Django 不熟悉。您的问题似乎是在 ASCI 中表示文本数据,而实际上是在 unicode 中。请尝试 Python.

中的 unidecode 模块
from unidecode import unidecode
#print(string) is replaced with 
print(unidecode(string))

参考Unidecode

我认为真正的问题出在 django 代码中。

六年前的报道:

https://code.djangoproject.com/ticket/18063

我认为 django 的补丁可以解决它:

def __repr__(self):
    return self.....encode('ascii', 'replace')

我认为 repr() 方法应该 return“7 位 ascii”。