如何在 SQLAlchemy 的`create_engine` 中使用`charset` 和`encoding`(创建pandas 数据框)?

Posted

技术标签:

【中文标题】如何在 SQLAlchemy 的`create_engine` 中使用`charset` 和`encoding`(创建pandas 数据框)?【英文标题】:how to use `charset` and `encoding` in `create_engine` of SQLAlchemy (to create pandas dataframe)? 【发布时间】:2017-12-29 23:55:09 【问题描述】:

我对 SQLAlchemy 中 charset 和 encoding 的工作方式感到非常困惑。我了解(并已阅读)charsets and encodings 之间的区别,并且我对the history of encodings 有很好的了解。

我在 latin1_swedish_ci 中的 mysql 中有一个表为什么?可能因为this)。我需要创建一个 pandas 数据框,在其中我得到正确的字符(而不是奇怪的符号)。最初,这是在代码中:

connect_engine = create_engine('mysql://user:password@1.1.1.1/db')
sql_query = "select * from table1"
df = pandas.read_sql(sql_query, connect_engine)

我们开始遇到Š 字符的问题(对应于u'\u0160' unicode,但我们得到的是'\x8a')。我希望这会起作用:

connect_engine = create_engine('mysql://user:password@1.1.1.1/db', encoding='utf8') 

但是,我继续得到'\x8a',我意识到这是有道理的,因为编码参数的默认值是utf8。所以,然后,我尝试encoding='latin1' 来解决这个问题:

connect_engine = create_engine('mysql://user:password@1.1.1.1/db', encoding='latin1')

但是,我仍然得到相同的 '\x8a'。需要明确的是,在这两种情况下(encoding='utf8'encoding='latin1'),我可以使用mystring.decode('latin1'),但不能使用mystring.decode('utf8')

然后,我重新发现了连接字符串中的charset 参数,即'mysql://user:password@1.1.1.1/db?charset=latin1'。在尝试了所有可能的字符集和编码组合之后,我发现这个可行:

connect_engine = create_engine('mysql://user:password@1.1.1.1/db?charset=utf8')

如果有人能解释我如何正确使用连接字符串中的charset,以及create_engine 中的encoding 参数,我将不胜感激?

【问题讨论】:

【参考方案1】:

encoding 参数不能正常工作。

因此,正如@doru 在this link 中所说,您应该在连接字符串的末尾添加?charset=utf8mb4。像这样:

connect_string = 'mysql+pymysql://:@:/?charset=utf8mb4'.format(DB_USER, DB_PASS, DB_HOST, DB_PORT, DATABASE)

【讨论】:

这以一种意想不到的方式救了我。是否存在其他已知问题,驱动程序/DBAPI 选择 latin1 并忽略服务器端设置?我在服务器上有这个设置,不知道为什么我也需要在连接器上设置它来修复问题。【参考方案2】:

encoding 是用于编码/解码的编解码器在 SQLAlchemy 中。来自文档:

对于那些检测到 DBAPI 不支持 Pythonunicode对象,这个编码是用来判断 源/目标编码。它不用于 DBAPI 直接处理 unicode。

[...]

要正确配置系统以容纳 Python unicode 对象, DBAPI 应配置为最大程度地处理 unicode 适当的程度[...]

mysql-python 直接处理 unicode,所以不需要使用这个设置。

charset 是特定于 mysql-python 驱动程序的设置。来自the documentation:

此字符集是连接的客户端字符集

此设置控制服务器上的three variables,特别是character_set_results,这是您感兴趣的。设置后,字符串将作为unicode 对象返回。

请注意,这仅适用于数据库中有 latin1 编码数据的情况。如果您已将 utf-8 字节存储为 latin1,则改用 encoding 可能会更好。

【讨论】:

感谢@univerio,我还是有点迷茫,因为有几个名字,我不打算放置它们:database -> python driver -> mysql-python interface (DBAPI?) -> SQLALchemy。驱动和接口、DBAPI一样吗? @toto_tico 驱动和 DBAPI 是一回事。 (从技术上讲,DBAPI 是 PEP 249 定义的接口,驱动程序是实现此接口的库,但没必要这么迂腐。)所以它是 database -> driver/DBAPI -> SQLAlchemy i>.【参考方案3】:

我遇到了同样的问题。我刚刚在网址末尾添加了 ?charset=utf8mb4

这是我的:

之前

SQL_ENGINE = sqlalchemy.create_engine('mysql+pymysql://'+MySQL.USER+':'+MySQL.PASSWORD+'@'+MySQL.HOST+':'+str(MySQL.PORT)+'/'+MySQL.DB_NAME)

之后

SQL_ENGINE = sqlalchemy.create_engine('mysql+pymysql://'+MySQL.USER+':'+MySQL.PASSWORD+'@'+MySQL.HOST+':'+str(MySQL.PORT)+'/'+MySQL.DB_NAME + "?charset=utf8mb4")

【讨论】:

【参考方案4】:

这对我有用。

from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL

db_url = 
    'database': "dbname",
    'drivername': 'mysql',
    'username': 'myname',
    'password': 'mypassword',
    'host': '127.0.0.1',
    'query': 'charset': 'utf8',  # the key-point setting


engine = create_engine(URL(**db_url), encoding="utf8")

【讨论】:

以上是关于如何在 SQLAlchemy 的`create_engine` 中使用`charset` 和`encoding`(创建pandas 数据框)?的主要内容,如果未能解决你的问题,请参考以下文章

SQLAlchemy 如何跟踪数据库更改?

如何在 SQLAlchemy 的过滤条件中传递模型参数

如何在 SQLAlchemy 中正确添加数据?

如何在 SQLAlchemy 中加载嵌套关系?

如何在 SQLAlchemy 中定义无符号整数

SQLAlchemy:如何过滤日期字段?