Unicode与Alembic不一致



我有一个迁移,它正在运行一些依赖于unicode字符的自定义代码。我目前使用的是SQLAlchemy 1.1.9和Alembic 1.0.2。

我可以看到我的数据库和表都有正确的设置:

mysql> SELECT @@character_set_database, @@collation_database;
+--------------------------+----------------------+
| @@character_set_database | @@collation_database |
+--------------------------+----------------------+
| utf8mb4                  | utf8mb4_general_ci   |
+--------------------------+----------------------+

mysql> SHOW TABLE STATUS where name like 'mytable';
+---------+-----+--------------------+----------+----------------+---------+
| Name    | ... | Collation          | Checksum | Create_options | Comment |
+---------+-----+--------------------+----------+----------------+---------+
| mytable | ... | utf8mb4_unicode_ci |     NULL |                |         |
+---------+-----+--------------------+----------+----------------+---------+

我插入了一个字符串,Nguyễn Johñ(注意e和n都是unicode字符)。当我让我的flask应用程序加载行时,它会正确加载。但是当我运行迁移时,我看到alembic调试日志显示Nguy?n Johñ和我自己的调试日志打印相同的东西。

为什么一些unicode字符被转换成问号?(注意测试其他字符,我在终端中看到一些字符,一些转义,如"xa0",和其他的"?"

以下内容可能也很重要。

  • 发送给engine = create_engine()的URL具有utf8字符集
  • 我有以下代码运行迁移:
from sqlalchemy.sql import table, column
from sqlalchemy import String, Integer, Boolean, Date, Unicode
MyTable = table('mytable',
column('id', Integer),
column('test1', Unicode(collation='utf8mb4_unicode_ci')),
column('test2', Unicode),
)
...
def upgrade():
...
bind = op.get_bind()
session = orm.Session(bind=bind)
rows = session.query(MyTable).all()
print(rows)
  • 调试日志也显示以下内容,但我不确定这是否只是alembic自己的特征检测代码:
INFO  [sqlalchemy.engine.base.Engine] show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'
INFO  [sqlalchemy.engine.base.Engine] ()
DEBUG [sqlalchemy.engine.base.Engine] Col ('Collation', 'Charset', 'Id', 'Default', 'Compiled', 'Sortlen')
DEBUG [sqlalchemy.engine.base.Engine] Row ('utf8_bin', 'utf8', 83, '', 'Yes', 1)

发现了这个问题,这是一个很小但非常重要的疏忽。

我有engine = create_engine()在DB URL w/"charset=utf8"然而config.set_main_option('sqlalchemy.url', db_url)没有得到字符集。

一旦在两个地方都传递了字符集参数,一切都开始工作了。

我也可以确认Unicode(collation='utf8mb4_unicode_ci')是不必要的,只用Unicode()就足够了。

和DEBUG日志行仍然显示"utf8_bin"one_answers";utf8"所以我认为他们在做某种特征检测。

我只使用sqlite和mysql,所以我使用了这个片段:

if not db_url.startswith("sqlite"):
sep = "&" if "?" in db_url else "?"
db_url = "{db_url}{sep}charset=utf8".format(db_url=db_url, sep=sep)

我知道这对我的嫉妒很有效,但也可以适用于其他人。其他可能不需要阻止为sqlite添加字符集,并且可能不需要加密参数有时添加到DB URL。

相关内容

  • 没有找到相关文章

最新更新