如何使用mysql.connector从MySQL返回str?

mpgws1up  于 2023-01-01  发布在  Mysql
关注(0)|答案(6)|浏览(175)

I'm trying to use MySQL Connector/Python from mysql.com with Python 3.
我有UTF-8编码的表,当我取行时,所有的字符列都返回bytearray,这会造成一些混乱。
如何直接获取str
UPD:

# -*- coding: utf-8 -*-
import mysql.connector
con = mysql.connector.connect( user ="root", db = "vg_site_db", charset = 'utf8' )
cursor = con.cursor()
sql = """select caption from domains
"""
cursor.execute( sql )
row = cursor.fetchone()
while row is not None:
    print( row )
    row = cursor.fetchone()

输出:

(bytearray(b'ezsp.ru'),)
(bytearray(b'eazyshop.ru'),)
(bytearray(b'127.0.0.1:8080'),)
(bytearray(b'rmsvet.ru'),)

我想要:

('ezsp.ru',)
('eazyshop.ru',)
('127.0.0.1:8080',)
('rmsvet.ru',)

更新2:
我的表使用COLLATE utf8_bin

lskq00tm

lskq00tm1#

看起来当你使用二进制排序时会发生这种情况,至少我也是这样。要将字节数组转换成Unicode字符串,你可以添加一个自定义转换器类:

class MyConverter(mysql.connector.conversion.MySQLConverter):

    def row_to_python(self, row, fields):
        row = super(MyConverter, self).row_to_python(row, fields)

        def to_unicode(col):
            if isinstance(col, bytearray):
                return col.decode('utf-8')
            return col

        return[to_unicode(col) for col in row]

sql = mysql.connector.connect(converter_class=MyConverter, host=...)
z9ju0rcb

z9ju0rcb2#

当各个列使用 binary collation(例如utf8_bin)定义时,MySQL连接器将字符串(使用CHARVARCHARTEXT数据类型存储)返回为bytearray。您必须对值调用.decode()以获取Python字符串,例如:

for row in cursor:
    caption = row[0].decode()

也就是说,除非您有使用utf8_bin的特定要求,否则在数据库级别使用带有排序规则utf8mb4_unicode_ciutf8mb4字符集是一个更好的主意。这将解决您的问题并允许完全的Unicode支持。有关详细信息,请参阅thisthis

hec6srdp

hec6srdp3#

mysql-connector-python==8.0.17添加到requirements.txt为我解决了这个问题。

wqsoz72f

wqsoz72f4#

虽然投票最多的答案(@danmichaelo)当然有效,但我想提供我的版本,解决一个主要的“但是”,这已经由@Tominator指出;自定义转换器类现在必须继承MySQLConverterBase而不是MySQLConverter。您不希望继承MySQLConverter(即使如@danmichaelo所指出的,它继承了MySQLConverterBase)的原因是,它将在每个返回值上调用MySQLConverter类中的相应转换器。这将实现您可能不需要的逻辑。
为了避免上述情况,您有两种选择:第一,您可以创建一个更高级的函数,该函数将获取数据并在检索到行后更改这些行。

def get_data_from_db(cursor, sql_query):
    cursor.execute(sql)
    row = cursor.fetchone()
    while row is not None:
        row_to_return = row.decode('utf-8') if isinstance(row, bytearray) else row
        row = cursor.fetchone()
    
    return row

如果你仍然想使用定制的converter类方法,那么你应该按照文档中的建议继承MySQLConverterBasehttps://dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html在mysql-connector-python==8.0.26之前有效,见下文),然后你可以扩展MySQLConverterBase.to_python方法。

class MyConverter(mysql.connector.conversion.MySQLConverterBase):
    def to_python(self, vtype, value):
        """Convert MySQL data type to Python"""
        if isinstance(value, bytearray):
            return value.decode('utf-8')

        super().to_python(vtype, value)

P.S.类MyConverter可用于实现自定义转换器,方法是创建名称与MySQLConverter类相同的函数(在此处查找该类:例如,我希望将TINYINT转换为bool,并添加了名为MyConverter._TINY_to_python(self, value, desc=None)的方法
--更新mysql连接器-python==8.0.27--
在8.0.27版本中,如果你创建一个继承了MySQLConverterBase的转换器类,你可能会得到一个错误消息 “期望一个类似字节的对象,发现了str”。我不清楚为什么会发生这种情况,但是我上面关于创建定制转换器的回答似乎不再成立了。相反,你现在应该继承MySQLConverter类:

class MyConverter(mysql.connector.conversion.MySQLConverter):
    def to_python(self, vtype, value):
        """Convert MySQL data type to Python"""
        if isinstance(value, bytearray):
            return value.decode('utf-8')

        super().to_python(vtype, value)
nnt7mjpx

nnt7mjpx5#

我不认为你可以让游标返回字符串,MySQL Connector Documentation说他们选择返回字节数组,这样他们只需要为Python2和Python3维护一个代码库:
使用“原始”游标,返回的值是bytearray类型,这对于Python 2和Python 3返回相同的数据是必要的。
我使用列表解析来解码行中的每个字节数组,从而解决了这个问题:

for row in cursor:
    type_fixed_row = tuple([el.decode('utf-8') if type(el) is bytearray else el for el in row])
    print( type_fixed_row )
iszxjhcz

iszxjhcz6#

解决这个问题的一个简单方法是确保您正在从MySQL表中检索"字符串"。为此,您只需在查询中添加CAST,如下所示:

# -*- coding: utf-8 -*-
import mysql.connector
con = mysql.connector.connect( user ="root", db = "vg_site_db", charset = 'utf8' )
cursor = con.cursor()
sql = "select CAST(caption as CHAR(50)) from domains"
cursor.execute( sql )
row = cursor.fetchone()
while row is not None:
    print( row )
    row = cursor.fetchone()

这应该对你有用。

相关问题