无法将 character_set_results 设置为 latin1
我决定第一次使用Django 1.7和Python 3。
我需要处理一个包含utf8
数据的旧latin1
数据库。我知道这很糟糕,但数据库太大了,真的没办法改动。所以我尝试了以下方法:
DATABASES = {
'ENGINE' : 'django.db.backends.mysql', // using MySQL-python fork with support for py3
...
'OPTIONS' : {
'init_command': "SET character_set_results = 'latin1'",
#'read_default_file': '/etc/my.cnf.d/client.cnf', // I've also tried this one
}
}
我还尝试了Oracle的python-mysql-connector,设置如下:
DATABASES = {
'ENGINE' : 'mysql.connector.django', // using MySQL-python fork with support for py3
'OPTIONS' : {
'option_files': ['/etc/my.cnf.d/client.cnf'],
}
}
/etc/my.cnf.d/client.cnf
[client]
init-command='SET character_set_results = "latin1"'
# password, host, username
在这两种情况下,我都能连接到数据库,但似乎Django把字符集结果设置回了utf8。
我尝试了以下方法:
from django.db import connection
with connection.cursor() as c:
// I expect variable to be 'latin1'
c.execute("show variables like 'character_set_results%'")
c.fetchone() // returns ('character_set_results', 'utf8')
// here I try to set it manually
c.execute("SET character_set_results = 'latin1'")
c.execute("show variables like 'character_set_results%'")
c.fetchone() // returns ('character_set_results', 'latin1') // now it's OK
- 我确定Django使用的是
client.cfg
文件和正确的[section]
,因为它包含了用户名和密码,并且成功连接到了数据库。 - 当我在Linux终端使用
mysql
命令时,它使用的是同一个配置文件,一切都按预期工作。
所以我猜Django以某种方式强制将character_set_results
变量设置为utf8
。这可能吗?有没有办法解决这个问题?
非常感谢!
3 个回答
在你使用的客户端配置文件 client.cfg 中,针对 MySQL 连接器,不要使用 init-command 这个选项,因为连接器会忽略它。你可以用 write 和 charset=latin1 来代替,这样就可以正常工作了。
[client]
charset=latin1
# password, host, username
这不是一个完整的答案,但评论太长了,所以我就单独说一下。
Django的MySQL封装默认会在DatabaseWrapper.get_connection_params()
中设置kwargs['charset']='utf8'
。这个设置会被传递给MySQLdb的Connection.__init__
,而这个文档中提到:
字符集
如果提供了这个参数,连接的字符集将会被更改为这个字符集(MySQL-4.1及更新版本)。这意味着
use_unicode=True。
所以一个起点可能是直接在你的OPTIONS
字典中添加"charset":"latin1"
?
警告:我不确定这样做能否解决你的问题,甚至可能会引发其他问题,但把utf8编码的数据放在一个latin1的数据库里,肯定不是个好主意 :-/(我也经历过这个,我能理解你的痛苦)。
我终于搞明白了(我也不知道为什么每次在Stack Overflow发帖后过一段时间才找到解决办法)
from django.db.backends.signals import connection_created
def connection_setup(**kwargs):
conn = kwargs['connection']
with conn.cursor() as cursor:
cursor.execute("SET character_set_results = 'latin1'")
cursor.close()
我之前试过用Oracle的 python-mysql-connector
,结果出现了
RuntimeError: maximum recursion depth exceeded in comparison
但是用 MySQL-driver
的py3版本就没问题。我猜这可能是 python-mysql-connector
或者 Django
的一个bug,我会去报告一下。希望这能帮到别人。