UnicodeDecodeError с использованием Django и format-строк
Я написал небольшой пример проблемы для всех, чтобы увидеть, что происходит с использованием 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
выходы со следующим выходом + трассировка
$ 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)
есть ли у кого-нибудь идея, что здесь происходит?
5 ответов
проблема здесь в том, что вы интерполируете UTF-8 bytestrings в строку Unicode. Ваш '%r'
string-это строка Unicode, потому что вы использовали from __future__ import unicode_literals
, а repr(group)
(используется %r
placeholder) возвращает bytestring. Для моделей Django,repr()
может включать данные Юникода в представление, закодированное в bytestring с помощью UTF-8. Такие представления не ASCII safe.
для вашего конкретного примера, repr()
на Group
экземпляра производит в bytestring '<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)
обратите внимание, что я не использовать from __future__ import unicode_literals
в моей сессии Python, поэтому '<Group: sch\xc3\xb6n>'
строку не
мне было трудно найти общее решение вашей проблемы.
__repr__()
это то, что я понимаю, должно вернуть 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-это беспорядок. Надеюсь, это прольет свет на то, как обойти (это единственный способ найти) проблему.
Я думаю, что реальная проблема заключается в коде django.
об этом сообщили шесть лет назад:
https://code.djangoproject.com/ticket/18063
Я думаю, что патч для django решит это:
def __repr__(self):
return self.....encode('ascii', 'replace')
Я думаю, что метод repr () должен возвращать "7 бит ascii".
Если это так, то нам нужно переопределить метод 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. Попробуйте модуль unidecode в Python.
from unidecode import unidecode
#print(string) is replaced with
print(unidecode(string))
Refer Unidecode