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

ссылка:https://docs.python.org/2/howto/unicode.html


Я не знаком с Django. Ваша проблема, похоже, представляет текстовые данные в ASCI, который на самом деле находится в unicode. Попробуйте модуль unidecode в Python.

from unidecode import unidecode
#print(string) is replaced with 
print(unidecode(string))

Refer Unidecode