django 1.5 + pymysql 错误:ImportError: 无法导入名称 Thing2Literal
我尝试使用django1.5,并且想用pymysql来替代MySQLdb,具体方法可以参考这里如何让Django与不支持的MySQL驱动一起工作,比如gevent-mysql或Concurrence的MySQL驱动?
在我的管理命令的开头:
+try:
+ import pymysql
+ pymysql.install_as_MySQLdb()
+except ImportError:
+ pass
但是出现了错误:
/local/lib/python2.7/site-packages/django/db/backends/mysql/base.py", line 30, in <module>
from MySQLdb.converters import conversions, Thing2Literal
ImportError: cannot import name Thing2Literal
该怎么解决呢?
2 个回答
在 MySQLdb
中,如果你使用的是较新版本的 MySQL,就不会用到 Thing2Literal
方法。这种情况下,当连接可用时,会使用连接的 string_literal
方法。
你需要对 pymysql
进行一些修改,以便它也能这样做,并允许你使用连接的方法。
背景
这个方法是用来处理 SQL 语句中的特殊字符的。随意使用它可能会带来安全问题,这一点你需要考虑。
你想使用连接的方法的原因是字符集(charset),它在处理特殊字符时起着重要作用。
解决 ImportError
问题
这个问题比较简单,你只需要在 pymysql.converters
中实现一个虚拟的 Thing2Literal
方法。反正我们不会调用它,所以不需要太在意:
def _Thing2Literal(o,d):
"""
Implemented for compatibility with Django.
This function is overriden by the connection's escape method when one is available.
"""
raise NotImplementedError('Thing2Literal is only implemented through the Connection object.')
Thing2Literal = _Thing2Literal
在连接可用时动态修改 Thing2Literal
在 pymysql.connections.Connection
中,添加:import pymysql.converters
在 pymysql.connections.Connection.__init__
的末尾,添加以下内容:
pymysql.converters.Thing2Literal = lambda o, d: self.escape(o)
在 pymysql.connections.Connection.__del__
的末尾,添加相反的内容:
pymysql.converters.Thing2Literal = pymysql.converters._Thing2Literal
我们可以忽略 d
参数,因为它是一个包含现有转换的字典,这些转换已经可以通过 Connection.escape
方法使用。
注意事项
这可能会导致问题,并暴露出安全隐患。
此外,如果你有多个活动连接使用 不同 的字符集,这可能会出现严重的问题。
你可能还需要对 Django 进行一些调整,以确保它在可用时使用你修改过的版本——也就是说,把 from MySQLdb.converters import Thing2Literal
替换成其他内容,以便仍然将 Thing2Literal
绑定到模块。
当然,你也可以通过不修改 Django,而让 _Thing2Literal
函数更聪明来实现同样的效果。
我刚刚在使用Django 1.5.1和PyMySQL 0.5的时候遇到了同样的问题。
我通过使用CMGS的一个分支版本(https://github.com/CMGS/PyMySQL)来解决了这个问题。希望这个改进能被纳入到主版本的PyMySQL中。你可以在这里查看CMGS的请求:https://github.com/petehunt/PyMySQL/pull/106。
根据作者的评论和在请求中的反馈,我觉得这个版本在生产环境中使用是相当可靠的。
下面是一个requirements.txt文件中的示例行:
-e git://github.com/CMGS/PyMySQL.git#egg=PyMySQL-dev