使用sqlalchemy强制执行列编码

时间:2013-09-01 17:49:23

标签: python mysql encoding utf-8 sqlalchemy

我正在使用sqlalchemy来创建我的数据库的架构。无论我怎么做,我都没有成功地使用utf-8。

这是一个重新创建我的问题的最小python脚本:

from sqlalchemy import create_engine, Column, Unicode
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('mysql+mysqldb://user:password@localhost/multidic?charset=utf8', echo=True)
Base = declarative_base()
class MyTableName(Base):
    __tablename__ = "mytablename"
    test_column = Column(Unicode(2),primary_key=True)
Base.metadata.create_all(engine)

运行此脚本后,当我查看数据库时,我发现编码是latin1而不是utf-8:

mysql> SHOW FULL COLUMNS FROM mytablename;
+-------------+------------+-------------------+------+-----+---------+-------+---------------------------------+---------+
| Field       | Type       | Collation         | Null | Key | Default | Extra | Privileges                      | Comment |
+-------------+------------+-------------------+------+-----+---------+-------+---------------------------------+---------+
| test_column | varchar(2) | latin1_swedish_ci | NO   | PRI | NULL    |       | select,insert,update,references |         |
+-------------+------------+-------------------+------+-----+---------+-------+---------------------------------+---------+
1 row in set (0.00 sec)

我尝试更改创建的列的类型(字符串而不是 Unicode ),并尝试添加参数 encoding =“utf8”< / strong>在 create_engine 的调用中,但都没有效果。

所以,我的问题是:

如何使用sqlalchemy强制在MySQL中强制使用给定的字符编码(在我的情况下是utf-8)?

谢谢:)

说明:

我正在使用sqlalchemy 0.7和python 2.7;我可以升级其中一个或两个,但前提是它是唯一的解决方案!

我有mysql 5,它支持utf-8:

mysql> show character set where charset="utf8";
+---------+---------------+-------------------+--------+
| Charset | Description   | Default collation | Maxlen |
+---------+---------------+-------------------+--------+
| utf8    | UTF-8 Unicode | utf8_general_ci   |      3 |
+---------+---------------+-------------------+--------+
1 row in set (0.00 sec)

2 个答案:

答案 0 :(得分:16)

要为每列指定特定的排序规则,请在数据类型上使用collation参数:

class MyTableName(Base):
    __tablename__ = "mytablename2"
    test_column = Column(Unicode(2),
                         primary_key=True)
    test_column2 = Column(Unicode(2, collation='utf8_bin'))
#                                    ^^^^^^^^^^^^^^^^^^^^

请注意,MySQL将此理解为描述文本的代码点集以及文本将被编入索引的排序顺序;像'utf8'或'utf-8'这样的常见嫌疑人对MySQL不熟悉(使用SHOW COLLATION查看完整列表)

mysql> show full columns from mytablename2;
+--------------+------------+-------------------+------+-----+---------+-------+---------------------------------+---------+
| Field        | Type       | Collation         | Null | Key | Default | Extra | Privileges                      | Comment |
+--------------+------------+-------------------+------+-----+---------+-------+---------------------------------+---------+
| test_column  | varchar(2) | latin1_swedish_ci | NO   | PRI | NULL    |       | select,insert,update,references |         |
| test_column2 | varchar(2) | utf8_bin          | YES  |     | NULL    |       | select,insert,update,references |         |
+--------------+------------+-------------------+------+-----+---------+-------+---------------------------------+---------+
2 rows in set (0.00 sec)

mysql> 

答案 1 :(得分:2)

对我来说,校对参数不起作用。

我的连接字符串是:

db = create_engine('mysql+pymysql://user:pass@dbhost/schema?charset=utf8')

由于charset,Pymysql正在执行set name utf8,数据库正在将utf8转换为表的编码,导致数据丢失。

如果我离开charset,charset默认为latin1,pymysql尝试将我的utf8字符串编码为latin1,然后再将它们发送到数据库,从而导致UnicodeEncode错误。

这对我有用:session.execute(text("SET NAMES latin1")) 使数据库假定我发送的utf8字符串不需要转换。