使用Django将Unicode字符存储到MySQL时出现问题

时间:2009-07-09 08:04:20

标签: python mysql django unicode django-models

我有字符串

 u"Played Mirror's Edge\u2122"

哪个应该显示为

 Played Mirror's Edge™

但这是另一个问题。我的问题在于我将它放在模型中,然后尝试将其保存到数据库中。 AKA:

a = models.Achievement(name=u"Played Mirror's Edge\u2122")
a.save()

我得到了:

'ascii' codec can't encode character u'\u2122' in position 13: ordinal not in range(128)

完整堆栈跟踪(根据要求):

Traceback:
File "/var/home/ptarjan/django/mysite/django/core/handlers/base.py" in get_response
  86.                 response = callback(request, *callback_args, **callback_kwargs)
File "/var/home/ptarjan/django/mysite/yourock/views/alias.py" in import_all
  161.     types.import_all(type, alias)
File "/var/home/ptarjan/django/mysite/yourock/types/types.py" in import_all
  52.     return modules[type].import_all(siteAlias, alias)
File "/var/home/ptarjan/django/mysite/yourock/types/xbox.py" in import_all
  117.             achiever = self.add_achievement(dict, siteAlias, alias)
File "/var/home/ptarjan/django/mysite/yourock/types/base_profile.py" in add_achievement
  130.                 owner       = siteAlias,
File "/var/home/ptarjan/django/mysite/django/db/models/query.py" in get
  304.         num = len(clone)
File "/var/home/ptarjan/django/mysite/django/db/models/query.py" in __len__
  160.                 self._result_cache = list(self.iterator())
File "/var/home/ptarjan/django/mysite/django/db/models/query.py" in iterator
  275.         for row in self.query.results_iter():
File "/var/home/ptarjan/django/mysite/django/db/models/sql/query.py" in results_iter
  206.         for rows in self.execute_sql(MULTI):
File "/var/home/ptarjan/django/mysite/django/db/models/sql/query.py" in execute_sql
  1734.         cursor.execute(sql, params)
File "/var/home/ptarjan/django/mysite/django/db/backends/util.py" in execute
  19.             return self.cursor.execute(sql, params)
File "/var/home/ptarjan/django/mysite/django/db/backends/mysql/base.py" in execute
  83.             return self.cursor.execute(query, args)
File "/usr/lib/pymodules/python2.5/MySQLdb/cursors.py" in execute
  151.             query = query % db.literal(args)
File "/usr/lib/pymodules/python2.5/MySQLdb/connections.py" in literal
  247.         return self.escape(o, self.encoders)
File "/usr/lib/pymodules/python2.5/MySQLdb/connections.py" in string_literal
  180.                 return db.string_literal(obj)

Exception Type: UnicodeEncodeError at /import/xbox:bob
Exception Value: 'ascii' codec can't encode character u'\u2122' in position 13: ordinal not in range(128)

该模型的关键部分:

class Achievement(MyBaseModel):
    name = models.CharField(max_length=100, help_text="A human readable achievement name")

我在settings.py

中使用了MySQL后端
DEFAULT_CHARSET = 'utf-8'

基本上,我应该如何处理所有这些unicode的东西?如果我远离有趣的角色并坚持使用UTF8,我希望它能“正常工作”。唉,这似乎并不那么容易。

7 个答案:

答案 0 :(得分:12)

感谢在此发帖的所有人。它真的有助于我的unicode知识(并且让其他人学到了很多东西)。

因为我试图简化我的问题并且没有提供所有信息,所以我们似乎都在咆哮错误的树。似乎我没有使用“REAL”unicode字符串,而是使用BeautifulSoup.NavigableString将其自身重命名为unicode字符串。因此所有打印输出看起来都像unicode,但它们不是。

在MySQLDB库的某个深处,他们无法处理这些字符串。

这有效:

>>> Achievement.objects.get(name = u"Mirror's Edge\u2122")
<Achievement: Mirror's Edge™>

另一方面:

>>> b = BeautifulSoup(u"<span>Mirror's Edge\u2122</span>").span.string
>>> Achievement.objects.get(name = b)
... Exceptoins ...
UnicodeEncodeError: 'ascii' codec can't encode character u'\u2122' in position 13: ordinal not in range(128)

但这有效:

>>> Achievement.objects.get(name = unicode(b))
<Achievement: Mirror's Edge™>

所以,再次感谢所有的unicode帮助,我相信它会派上用场。但是现在......

警告:BeautifulSoup不会返回 REAL unicode字符串,应该在执行任何有意义的操作之前强制使用unicode()。

答案 1 :(得分:4)

一些评论:

  • Python 2.x有两种字符串类型

    • “str”,基本上是一个字节数组(所以你可以存储你喜欢的任何东西)
    • “unicode”,内部是UCS2 / UCS4编码的unicode
  • 这些类型的实例被视为“已解码”数据。内部表示是参考,因此您将外部数据“解码”到其中,并“编码”为某种外部格式。

  • 一个好的策略是在数据进入系统时尽早解码,并尽可能晚地编码。尝试尽可能地为系统中的字符串使用unicode。 (在这方面我不同意尼古拉)。

  • 此编码方面适用于Nicolai的答案。他获取原始的unicode字符串,并将其编码为utf-8。但是这个没有解决问题(至少不是一般),因为结果字节缓冲区仍然包含范围之外的字节(127)(我没有检查过) for \ u2122),这意味着你会再次遇到同样的异常。

  • 仍然Nicolai的分析认为你传递的是一个unicode字符串,但在系统的某个地方,这被认为是一个str实例。如果某个地方将str()函数应用于你的unicode参数就足够了。

  • 在这种情况下,Python使用所谓的默认编码,如果不更改它,则为ascii。有一个函数sys.setdefaultencoding,您可以使用它来切换到例如utf-8,但该功能仅在有限的上下文中可用,因此您无法在应用程序代码中轻松使用它。

  • 我的感觉是问题在于你所呼唤的层次更深层。不幸的是,我无法评论Django或MySQL / SQLalchemy,但我想知道在模型中声明'name'属性时是否可以指定unicode类型。在字段级别处理类型信息将是一种很好的数据库实践。也许还有CharField的替代品?!

  • 是的,您可以安全地在双引号(“)字符串中嵌入单引号('),反之亦然。

答案 2 :(得分:3)

您正在使用'unicode'类型的字符串。如果您的模型或SQL后端不支持它们或者不知道如何转换为UTF-8,那么只需自己进行转换即可。坚持使用简单的字符串(python类型str)并转换为

a = models.Achievement(name=u"Played Mirror's Edge\u2122".encode("UTF-8"))

答案 3 :(得分:1)

昨天我正在研究这个问题,我发现在连接字符串中添加“charset = utf8”和“use_unicode = 1”使其工作(使用SQLAlchemy,猜测它是同样的问题)。

所以我的字符串看起来像: “MySQL的://用户:通过@主机:3306 /数据库use_unicode = 1&安培;字符集= UTF8”

答案 4 :(得分:0)

我同意尼古拉的观点。我已经遇到过使用UTF-8的问题,即使在纯Python(2.5)中也是如此。

我终于使用了unicode函数(?):

entry    = unicode(sys.stdin, ENCODING)

如果记得很清楚,ENCODING取决于语言环境:

import sys, locale

ENCODING    = locale.getdefaultlocale()[1]
DEFAULT_ENCODING    = sys.getdefaultencoding()

也许看看Python Unicode HOWTO

答案 5 :(得分:0)

我遇到了与mysql和postgres类似的问题,但sqllite没有问题。

这就是我用postgres解决这个问题的方法(没有用mysql测试这个技巧但是id也可以解决它)

在你正在处理unicode字符串的文件中执行

from django.utils.safestring import SafeUnicode

并假设unistr是包含字符串的变量,执行

unistr = SafeUnicode(unistr)

在我的情况下,我正在从网站上抓取

给出问题的原始代码(ht是beautifulsoup对象): -

keyword = ht.a.string

修复: -

keyword = SafeUnicode(ht.a.string)

我不知道为什么或者SafeUnicode正在做什么,我所知道的是它解决了我的问题。

答案 6 :(得分:-1)

对我来说,撇号看起来很奇怪,如果不是这样的话:

u"Played Mirror\'s Edge\u2122"