Оказывается, проблема довольно неловкая. Короче говоря, большинство разновидностей и видов в типах строковых данных MySQL отображаются на один тип данных в интерфейсе MySQL с дополнительным флагом BINARY.
Таким образом, MySQL VARCHAR
, VARBINARY
и строковый литерал отображаются в один и тот же тип MySQLdb.constants.FIELD_TYPE.VAR_STRING
в определениях типа столбца, но имеют дополнительный флаг MySQLdb.constants.FLAG.BINARY
, когда тип является VARBINARY
или строка сопоставлена с сопоставлением *_bin
.
Несмотря на то, что есть тип MySQLdb.constants.FIELD_TYPE.VARCHAR
, я не смог выяснить, когда он используется. Как я уже сказал, MySQL VARCHAR
столбцы отображаются на FIELD_TYPE.VAR_STRING
.
Решение становится довольно хрупким, если ваше приложение использует истинные двоичные строки (например, вы храните изображения и извлекаете их с тем же соединением, что и текст), поскольку оно предполагает декодирование всех двоичных строк в Unicode. Хотя, это работает.
Как официальный документы заявляет:
Поскольку MySQL возвращает все данные в виде строк и ожидает, что вы преобразуете их самостоятельно. Это было бы настоящей болью в заднице, но на самом деле, _mysql может сделать это для вас. (И MySQLdb делает это за вас.) Чтобы выполнить автоматическое преобразование типов, вам нужно создать словарь конвертера типов и передать его в connect () в качестве параметра ключевого слова conv .
На практике настоящей болью в заднице может быть процесс создания собственного словаря конвертеров. Но вы можете импортировать файл по умолчанию из MySQLdb.converters.conversions
и пропатчить его, или даже пропатчить его на экземпляре Соединения. Хитрость заключается в том, чтобы удалить специальный конвертер для флага FLAG.BINARY
и добавить декодер для всех случаев. Если вы явно указываете параметр charset
для MySQLdb.connect
, он вызывает параметр use_unicode=1
, который добавляет декодер для вас, но вы можете сделать это самостоятельно:
>>> con = MySQLdb.connect(**params)
>>> con.converter[FIELD_TYPE.VAR_STRING]
[(128, <type 'str'>), (None, <function string_decoder at 0x01FFA130>)]
>>> con.converter[FIELD_TYPE.VAR_STRING] = [(None, con.string_decoder)]
>>> c = con.cursor()
>>> c.execute("SELECT %s COLLATE utf8_bin", u'м')
1L
>>> c.fetchone()
(u'\u043c',)
Возможно, вам потребуется сделать такой же взлом для FIELD_TYPE.STRING
, если потребуется.
Другим решением является передача явного use_unicode=0
в MySQLdb.connect
и выполнение всех расшифровок в вашем коде, но я бы не стал.
Надеюсь, это может быть кому-то полезно.