python - 使用 Django 将 Unicode 字符存储到 MySQL 时出现问题
Posted
技术标签:
【中文标题】python - 使用 Django 将 Unicode 字符存储到 MySQL 时出现问题【英文标题】:python - Problem storing Unicode character to MySQL with Django 【发布时间】:2010-11-09 07:16:19 【问题描述】:我有字符串
u"Played Mirror's Edge\u2122"
应该显示为
Played Mirror's Edge™
但这是另一个问题。我手头的问题是我将其放入模型中,然后尝试将其保存到数据库中。又名:
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,我希望这一切都能“正常工作”。唉,这似乎没那么容易。
【问题讨论】:
听起来好像不喜欢单引号(')字符... 怎么回事?我认为它在 \u2122 上很无聊...... 你能提供其余的堆栈跟踪吗?实际的数据库代码可能正确处理了您的 unicode 字符串,但是某处的某些日志记录代码搞砸了。 并尝试缩小问题:models.Achievement.objects.create(name=u"\u2122") models.Achievement.objects.create(name=u"Played Mirror's Edge") 你使用什么数据库排序规则? 【参考方案1】:感谢所有在这里发帖的人。它确实有助于我的 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() 强制执行。
【讨论】:
谢谢,通过谷歌找到了这个并从答案中学到了很多东西。然后我在最后读到你在用美丽的汤。跟我一样。 :) 即使在 BeautifulSoup 返回的所有值上强制使用 unicode 之后,我也无法使其工作。我在打印到终端和插入 MySQL 时都遇到错误。错误的形式为''latin-1' codec can't encode character u'\u03bc' in position 545: ordinal not in range(256)' 顺便说一句,lxml
也会发生同样的事情。如果您将文本从lxml
直接传递到 MySQLdb(其类型为 <type 'lxml.etree._ElementUnicodeResult'>
),则会收到相同的错误消息。【参考方案2】:
我同意尼古拉的观点。我已经遇到了使用 UTF-8 的问题,即使在纯 Python (2.5) 中也是如此。
我终于用上了unicode函数(?):
entry = unicode(sys.stdin, ENCODING)
编码取决于语言环境,如果我没记错的话:
import sys, locale
ENCODING = locale.getdefaultlocale()[1]
DEFAULT_ENCODING = sys.getdefaultencoding()
也许看看Python Unicode HOWTO?
【讨论】:
【参考方案3】:我在使用 mysql 和 postgres 时遇到了类似的问题,但使用 sqllite 没有问题。
这就是我用 postgres 解决问题的方法(没有用 mysql 测试这个技巧,但我认为它也会解决它)
在你处理 unicode 字符串的文件中做一个
from django.utils.safestring import SafeUnicode
并假设 unistr 是包含字符串的变量,执行
unistr = SafeUnicode(unistr)
就我而言,我是从网站上抓取的
出现问题的原始代码(ht 是 beautifulsoup 对象):-
keyword = ht.a.string
修复:-
keyword = SafeUnicode(ht.a.string)
我不知道 SafeUnicode 为何或在做什么,我只知道它解决了我的问题。
【讨论】:
来自 SafeUnicode 的文档 """ 一个 unicode 子类,专门标记为“安全”以用于 html 输出。“””我认为您只是使用该函数将其转换为 unicode。我确实使用了很多方法来获取数据,一些正则表达式 urllib2.open().read() 一些漂亮的汤。我以为 Beautiful Soup 默认使用 unicode...【参考方案4】:几点说明:
Python 2.x 有两种字符串类型
“str”,它基本上是一个字节数组(所以你可以在里面存储任何你喜欢的东西) "unicode",内部为UCS2/UCS4编码的unicode这些类型的实例被视为“解码”数据。内部表示是参考,因此您将外部数据“解码”到其中,然后将外部数据“编码”为某种外部格式。
一个好的策略是在数据进入系统时尽早解码,并尽可能晚地进行编码。尽量对系统中的字符串使用 unicode。 (在这方面我不同意 Nikolai)。
此编码方面适用于 Nicolai 的回答。他获取原始的 unicode 字符串,并将其编码为 utf-8。但这并没有解决问题(至少不是一般情况下),因为生成的字节缓冲区仍然包含范围之外的字节(127)(我没有检查对于 \u2122),这意味着您将再次遇到相同的异常。
Nicolai 的分析仍然认为您正在传递一个 unicode 字符串,但在系统的某个地方,这被视为 str 实例。如果在某个地方将 str() 函数应用于您的 unicode 参数就足够了。
在这种情况下,Python 使用所谓的默认编码,如果您不更改它就是 ascii。有一个函数 sys.setdefaultencoding 可以用来切换到例如utf-8,但该功能仅在有限的上下文中可用,因此您无法在应用程序代码中轻松使用它。
我的感觉是问题出在您调用的层的更深处。不幸的是,我无法评论 Django 或 MySQL/SQLalchemy,但我想知道在模型中声明“名称”属性时是否可以指定 unicode 类型。在字段级别处理类型信息将是一种很好的数据库实践。也许还有 CharField 的替代品?!
是的,您可以安全地将单引号 (') 嵌入双引号 (") 字符串中,反之亦然。
【讨论】:
谢谢,很好的信息。事实上,UTF8 也有与 ascii 相同的问题:unicode.encode(u"Played Mirror's Edge\u2122", 'utf8') "Played Mirror's Edge\xe2\x84\xa2"
。我一直在尝试使用 unicode(虽然我正在这样做),并且我的数据库是用 utf8 编码的。【参考方案5】:
对我来说,撇号看起来很奇怪,不应该这样转义吗:
u"Played Mirror\'s Edge\u2122"
【讨论】:
给定的字符串和你的是等价的。将其输入到 python 解释器中。 >>> u"玩过魔镜\u2122" u"玩过魔镜\u2122" >>> u"玩过魔镜\u2122" u"玩过魔镜\u2122" 撇号不必转义。转义不必转义的字符只会混淆代码。但你说得对,应该对不赞成票发表评论。【参考方案6】:您正在使用“unicode”类型的字符串。如果您的模型或 SQL 后端不支持它们或不知道如何转换为 UTF-8,则只需自己进行转换。坚持使用简单的字符串(python 类型 str)并像 in 一样转换
a = models.Achievement(name=u"Played Mirror's Edge\u2122".encode("UTF-8"))
【讨论】:
为什么对这个答案投反对票? Nikolai 似乎在我看来是在正确的轨道上注意到 Unicode not 与 UTF-8 相同... 如果我这样做,那么当我尝试在插入后打印模型时,我会从 force_unicode 得到 DjangoUnicodeDecodeError。如果我从数据库中获取它,那么它是完美的,但是打印最初插入的对象会抛出 DjangoUnicodeDecodeError。 :(【参考方案7】:我昨天正在处理这个问题,我发现在连接字符串中添加“charset=utf8”和“use_unicode=1”可以正常工作(使用 SQLAlchemy,猜想是同样的问题)。
所以我的字符串看起来像: "mysql://user:pass@host:3306/database?use_unicode=1&charset=utf8"
【讨论】:
查看 django 文件,在 ./db/backends/mysql/base.py 它有kwargs = 'conv': django_conversions, 'charset': 'utf8', 'use_unicode': True,
所以我认为它已经像这样连接了。以上是关于python - 使用 Django 将 Unicode 字符存储到 MySQL 时出现问题的主要内容,如果未能解决你的问题,请参考以下文章
python 使用eval报错NameError: name ‘null’ is not defined
Linux 下 将使用Python-Django开发的web应用布置到服务器上(亲测有效)
使用 Python 3/Django,如何将 MySql 表数据导出为 YAML 文件?
使用 Django/Python 将批量 .csv 数据上传到 webapp 的好方法是啥?