Результат SQLAlchemy для столбца UTF-8 имеет тип 'str', почему?
У меня есть SQL-запрос, который я выполняю с помощью механизма SQLAlchemy:
result = engine.execute('SELECT utf_8_field FROM table')
База данных - это MySQL, а тип столбца - TEXT с кодировкой UTF-8. Тип возвращаемого utf_8_field - "str", даже если я устанавливаю параметр convert_unicode = True при создании движка. Теперь случается так, что если в моей строке есть символ "é" (который не находится в 7-разрядном ASCII, но находится в расширенном наборе ASCII), я получаю UnicodeDecodeError при попытке выполнить это:
utf_8_field.encode("utf-8")
Точная ошибка:
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 1: ordinal not in range(128)
При изучении этого я обнаружил, что str.encode не поддерживает расширенный набор символов ASCII! Я нахожу это действительно странным, но это еще один вопрос.
Я не понимаю, почему SQLAlchemy не дает мне строку unicode. Раньше я использовал DB-API, и он работал нормально. У меня также нет табличных объектов SQLAlchemy для моих таблиц, поэтому я использую команду execute.
Любая идея?
Ответы
Ответ 1
Если вы хотите, чтобы данные были преобразованы автоматически, вы должны указать кодировку при создании движка:
create_engine('mysql+mysqldb:///mydb?charset=utf8')
Настройка use_unicode
сама по себе не укажет sqlalchemy, какую кодировку использовать.
Ответ 2
Чтобы преобразовать из UTF-8 bytestring в объект unicode, вам необходимо декодировать:
utf_8_field.decode('utf8')
Кроме того, при выполнении raw SELECT
через .execute
SQLAlchemy не имеет метаданных для разработки того, что ваш запрос возвращает данные utf-8, поэтому он не преобразует эту информацию в unicode для вас.
Другими словами, convert_unicode
работает только в том случае, если вы используете SQL-выражение SQLAlchemy API или функциональность ORM.
EDIT: как указано, ваши данные даже не кодируются кодировкой UTF-8; 0xe9
в UTF-8 будет указывать символ между \u9000
и \u9fff
, которые являются унифицированными идеологами CJK, пока вы сказали, что это символ латинского-1, код UTF-8 которого начинается с 0xc3
. Это, вероятно, ISO-8859-1
(латинский-1) или похожий:
>>> u'é'.encode('ISO-8859-1')
'\xe9'
Затем следует сказать, что SQLAlchemy соединяется с другим набором символов, используя параметр charset=utf8
, как указано @mata.