【问题标题】:enforce column encoding with sqlalchemy使用 sqlalchemy 强制列编码
【发布时间】:2013-09-04 20:27:57
【问题描述】:

我正在使用 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)

我尝试更改所创建列的类型(String 而不是 Unicode),并尝试添加参数 encoding = "utf8" 在对 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)

【问题讨论】:

  • 我记得上次我使用 MySql 时,我最终在 四个 的地方声明了 utf-8,比如在全局 conf 中,在表 def 中,在连接对象上,并且在进行查询时。也就是说,我根本没有理由使用 MySql(THESE IDTS USE LATIN-1 WITH SWEDISH COLLATION AS DEFAULT)。如果我想要一个 SQL 数据库,那么我会使用 Postgresql,它是免费的、良好的文档、合理的设计和快速的。——没有十匹马可以把我拉回 ORM/SqlAlchemy 的潮流;它的功能感觉太复杂了,并且以 SqlA 样式表示的查询*并不比文字 SQL 更具可读性。

标签: python mysql encoding utf-8 sqlalchemy


【解决方案1】:

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

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

请注意,MySQL 将其理解为描述文本的代码点集以及文本将被索引的排序顺序; MySQL 不会熟悉像 'utf8' 或 'utf-8' 这样的常见嫌疑人(使用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> 

【讨论】:

  • 尝试test_column2 = Column(Unicode(2, collation='utf8_bin')) 会引发错误:TypeError: __init__() got an unexpected keyword argument 'collation' ... 此外,尝试test_column2 = Column(Unicode(2), collation='utf8_bin') 会引发另一个错误:sqlalchemy.exc.ArgumentError: Unknown arguments passed to Column: ['collation']
  • 正是世界所需要的——一个将编码与排序混淆并调用编码“字符集”的数据库。您是否知道 Latin-1 自从 在 1999 年 被 Latin-9 = ISO-8859-15 取代后就严重过时了? Latin-1 甚至没有欧元符号。
  • 升级到最新版本的 SQLalchemy(即 0.8.2)使您的解决方案有效...谢谢!!
【解决方案2】:

对我来说,排序规则参数不起作用。

我的连接字符串是:

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

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

如果我将字符集排除在外,则字符集默认为 latin1,并且 pymysql 在将它们发送到数据库之前尝试将我的 utf8 字符串编码为 latin1,从而引发 UnicodeEncode 错误。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 2013-08-29
    • 1970-01-01
    • 2021-06-17
    • 2017-03-13
    • 2018-09-11
    • 1970-01-01
    相关资源
    最近更新 更多