2

今天我通过 Django 管理员收到了无法编码的数据。不知何故,数据的编码不是 unicode。这怎么可能?

我的模型中有一个name属性,Client它以 unicode 格式返回数据:

@property
def name(self):
    return u'{0} {1}'.format(self.firstname, self.lastname).strip()

但这不起作用:

>>> client
<Client: [Bad Unicode data]>

>>> client.lastname
'Dani\xc3\xabl'

>>> client.lastname.__class__
<type 'str'>

>>> u"{0} {1}".format(client.firstname, client.lastname)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 4: ordinal not in range(128)

足够奇怪,将名字/姓氏编码为常规字符串确实有效:

>>> "{0} {1}".format(client.firstname, client.lastname)
'Test Dani\xc3\xabl'

>>> "{0} {1}".format(client.firstname, client.lastname).decode('utf-8')
u'Test Dani\xebl'

这里发生了什么?这个输入是如何通过管理员进入我的模型的?

系统堆栈(它是一个外部服务器):

  • Debian 6.0.5(挤压)
  • Django 1.4.1
  • Python 2.6.6
  • MySQL 5.1.49
  • MySQL-python==1.2.2

这是相关的模型代码:

class Client(models.Model):
    firstname = models.CharField(_("Firstname"), max_length=255)
    lastname = models.CharField(_("Lastname"), max_length=255)
    email = models.EmailField(_("Email"), unique=True, max_length=255)

    class Meta:
        db_table = u'clients'
        ordering = ('firstname', 'lastname', 'email')

    def __unicode__(self):
        return u'{0} <{1}>'.format(self.name, self.email)

    @property
    def name(self):
        return u'{0} {1}'.format(self.firstname, self.lastname).strip()
4

1 回答 1

3

这可能是由于您用于 MySQL 数据库的排序规则。

实际上,Django 的行为是在从数据库中检索数据时始终返回unicode字符串——这将适用于您的代码,因为它没有任何问题。

但是,正如您在关于数据库设置的 django 文档中看到的,部分排序规则设置,使用 MySQLdb 版本 1.2.2 和排序的utf8_binMySQL 数据库将导致您在从数据库中检索字符字段时获取的不是 unicode 字符串,而是字节字符串。

您可能想要调查此问题(即检查您的 MySQL 排序规则设置),但您的问题很可能来自那里。

如果是这种情况,您将不得不手动解码从 MySQL 获得的任何输入。或者,您可以更改数据库的排序规则设置。

您可以使用SHOW TABLE STATUS FROM %YOURDB%来获取数据库中表的排序规则。


 摘自相关文档部分:

默认情况下,对于 UTF-8 数据库,MySQL 将使用 utf8_general_ci_swedish 排序规则。这会导致所有字符串相等比较以不区分大小写的方式进行。也就是说,“Fred”和“freD”在数据库级别被认为是相等的。如果您对字段有唯一约束,则尝试将“aa”和“AA”都插入同一列是非法的,因为它们与默认排序规则比较相等(因此,非唯一)。

在许多情况下,此默认设置不会有问题。但是,如果您确实想要对特定列或表进行区分大小写的比较,则可以更改列或表以使用 utf8_bin 排序规则。在这种情况下要注意的主要事情是,如果您使用的是 MySQLdb 1.2.2,那么 Django 中的数据库后端将为它从数据库接收的任何字符字段返回字节字符串(而不是 unicode 字符串)。这与 Django 总是返回 unicode 字符串的正常做法有很大的不同。

于 2012-09-01T11:44:38.257 回答