Django Unicode 解码错误: [坏的 Unicode 数据]

4

模型:

class ItemType(models.Model):
  name = models.CharField(max_length=100)
  def __unicode__(self):
    logger.debug("1. Item Type %s created" % self.name)
    return self.name 

代码:

  (...)
    type = re.search(r"Type:(.*?)",text)
    itemtype = ItemType.objects.create(name = name.group(1), defaults={'name':name.group(1)})
    logger.debug("2. Item Type %s created" % name.group(1))
    logger.debug("4. Item Type %s created" % itemtype.name)
    logger.debug("3. Item Type %s created" % itemtype)

结果令人意外(当然仅对我而言):

第一个logger.debug正如预期地打印出了Item Type ąęńłśóć created,但是第二个则引发了错误:

DjangoUnicodeDecodeError: 'ascii' codec can't decode byte  in position : 
ordinal not in range(128). 
You passed in <ItemType: [Bad Unicode data]> (<class 'aaa.models.ItemType'>)

为什么会出现错误,我该如何修复?

(文本是带有utf-8编码的html响应)

更新

我在模型中添加了调试,结果显示:

2014-10-06 09:38:53,342 DEBUG views 2. Item Type ąęćńółśż created
2014-10-06 09:38:53,342 DEBUG views 4. Item Type ąęćńółśż created
2014-10-06 09:38:53,344 DEBUG models 1. Item Type ąęćńółśż created
2014-10-06 09:38:53,358 DEBUG models 1. Item Type ąęćńółśż created

所以为什么调试3无法打印出来? 更新2 问题在这里:
  itemtype = ItemType.objects.create(name = name.group(1), defaults={'name':name.group(1)})

如果我将它变成

  itemtype = ItemType.objects.create(name = name.group(1), defaults={'name':u'ĄĆĘŃŁÓŚ'})

一切都很好。

那么如何将其转换为Unicode? unicode(name.group(1))无效。


你在使用哪个数据库?是Oracle吗?另外,你能否尝试更改为logger.debug("1. Item Type %s created", self.name)。在记录器中避免使用“%”。 - fragles
已更改为 logger.debug(itemtype),仍出现相同错误。 - Tomasz Brzezina
当您将包含非英语字符(Unicode字符超过128个)的Unicode字符串传递给期望ASCII字节串的内容时,就会出现此错误。Python字节串的默认编码是ASCII,“它处理正好128个(英语)字符”。这就是为什么尝试转换超过128个Unicode字符会产生错误的原因。请参见http://www.saltycrane.com/blog/2008/11/python-unicodeencodeerror-ascii-codec-cant-encode-character/。 - fragles
你的Postgres配置接受Unicode了吗? - fragles
是的,Postgres已正确配置。但如果我将u"żółć"添加到正则表达式结果模型调试打印预期值,我不同意它需要ASCII。我认为我必须对结果进行编码,但是如何进行编码和Unicode却无效。 - Tomasz Brzezina
1个回答

3

经过两天的奋斗,我找到了一个解决方案。这不是对于这种情况的绕过方式,而是思维的复杂变化,并且我需要重构整个代码。

  1. 我的假设是每个字符串都是UNICODE编码。如果不是,请修复它。

  2. 不要使用"%s"或"something",始终使用u"%s"和u"cośtam"

  3. 在每个具有models.CharField()或其他“文本”导向字段的模型中,我覆盖save()方法:

例如:

class ItemType(models.Model):
  name = models.CharField(max_length=100)

  def save(self, *args, **kwargs):
    if isinstance(self.name, str):
      self.name=self.name.decode("utf-8")
    super(ItemType, self).save(*args, **kwargs)

解释 - 如果名称填充了字符串而非Unicode - 将其更改为Unicode。

我是如何发现这个问题的:

我想知道models.CharField中的文本类型是什么,发现如果使用Unicode填充它,则它是Unicode,如果使用字符串填充则是字符串。因此,如果您曾经用Unicode“手动”填写它,并且在其他地方使用正则表达式用字符串填写它,则结果是意外的。

Unicode和字符串的最大问题是两者都可以使用变音符号:

>>> text_str = "żółć"
>>> text_unicode = u"żółć"
>>> print text_str
żółć
>>> print text_uni
żółć

所以你看不出区别。

但是如果你使用其他命令:

>>> text_str
'\xc5\xbc\xc3\xb3\xc5\x82\xc4\x87'
>>> text_uni
u'\u017c\xf3\u0142\u0107'

区别显而易见。

如果有一些设置可以改变打印(和类似的)行为为以下方式:

>>> print text_str
'\xc5\xbc\xc3\xb3\xc5\x82\xc4\x87'
>>> print text_uni
żółć

如果你能看到变音符号,那么一切调试都会变得更容易,否则就会很困难。

使用decode('utf-8')可以帮助解决问题:

>>> text_str
'\xc5\xbc\xc3\xb3\xc5\x82\xc4\x87'
>>> text_str.decode('utf-8')
u'\u017c\xf3\u0142\u0107'
>>> text_uni
u'\u017c\xf3\u0142\u0107'

大功告成!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接