Django管理员输入导致UnicodeDecodeError,怎么样?

时间:2012-09-01 11:03:19

标签: python django unicode python-unicode

今天我通过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-蟒== 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()

1 个答案:

答案 0 :(得分:3)

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

实际上,Django的行为是在从数据库中检索数据时始终返回unicode字符串 - 这可以与您的代码一起使用,因为它没有任何问题。

但是,正如您在the django documentation on database settings中所看到的,使用MySQLdb版本1.2.2和utf8_bin整理的MySQL数据库的部分整理设置将导致您不能获取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字符串的常规做法的一个很大的变化。