Недавно у меня была та же проблема со значением поля, являющимся байтовой строкой вместо юникода.Вот небольшой анализ.
Обзор
В общем, все, что нужно для получения Unicode-значений от курсора, это передать аргумент charset
конструктору соединений и иметь недвоичные поля таблицы(например, utf8_general_ci
).Передача use_unicode
бесполезна, поскольку она имеет значение true, когда charset
имеет значение.
MySQLdb учитывает типы полей описания курсора, поэтому, если в курсоре есть столбец DATETIME
, значения будут преобразованы вЭкземпляры Python datatime.datetime
, DECIMAL
до decimal.Decimal
и т. Д., Но двоичные значения будут представлены как есть байтовыми строками.Большинство декодеров определены в MySQLdb.converters
, и их можно переопределить на основе экземпляра, предоставив аргумент conv
конструктору соединения.
Но декодеры Unicode здесь являются исключением, что, вероятно, является недостатком дизайна.Они добавляются непосредственно к конвертерам экземпляра соединения в его конструкторе.Таким образом, их можно переопределить только на instance-basic.
Обходной путь
Давайте посмотрим код ошибки.
import MySQLdb
connection = MySQLdb.connect(user = 'guest', db = 'test', charset = 'utf8')
cursor = connection.cursor()
cursor.execute(u"SELECT 'abcdё' `s`, ExtractValue('<a>abcdё</a>', '/a') `b`")
print cursor.fetchone()
# (u'abcd\u0451', 'abcd\xd1\x91')
print cursor.description
# (('s', 253, 6, 15, 15, 31, 0), ('b', 251, 6, 50331648, 50331648, 31, 1))
print cursor.description_flags
# (1, 0)
Это показывает, что поле b
возвращается какстрока байтов вместо юникода.Однако это не двоичный файл, MySQLdb.constants.FLAG.BINARY & cursor.description_flags[1]
( MySQLdb field flags ).Похоже, ошибка в библиотеке (открыт # 90 ).Но причину этого я вижу как MySQLdb.constants.FIELD_TYPE.LONG_BLOB
(cursor.description[1][1] == 251
, типы полей MySQLdb ) просто не имеет преобразователя вообще.
import MySQLdb
import MySQLdb.converters as conv
import MySQLdb.constants as const
connection = MySQLdb.connect(user = 'guest', db = 'test', charset = 'utf8')
connection.converter[const.FIELD_TYPE.LONG_BLOB] = connection.converter[const.FIELD_TYPE.BLOB]
cursor = connection.cursor()
cursor.execute(u"SELECT 'abcdё' `s`, ExtractValue('<a>abcdё</a>', '/a') `b`")
print cursor.fetchone()
# (u'abcd\u0451', u'abcd\u0451')
print cursor.description
# (('s', 253, 6, 15, 15, 31, 0), ('b', 251, 6, 50331648, 50331648, 31, 1))
print cursor.description_flags
# (1, 0)
Таким образом, манипулируя экземпляром соединения converter
dict, можно добиться желаемого поведения декодирования Unicode.
Если вы хотите переопределить поведение, вот как выглядит запись dict для возможного текстового поля после конструктора.
import MySQLdb
import MySQLdb.constants as const
connection = MySQLdb.connect(user = 'guest', db = 'test', charset = 'utf8')
print connection.converter[const.FIELD_TYPE.BLOB]
# [(128, <type 'str'>), (None, <function string_decoder at 0x7fa472dda488>)]
MySQLdb.constants.FLAG.BINARY == 128
.Это означает, что если поле имеет двоичный флаг, оно будет str
, в противном случае будет применен декодер Unicode.Таким образом, вы также хотите попытаться преобразовать двоичные значения, вы можете получить первый кортеж.