Recientemente tuve el mismo problema con el valor de campo que es una cadena de bytes en lugar de unicode. Aquí hay un pequeño análisis.
general
En general todo lo que uno tiene que hacer para tener valores Unicode de un cursor, es pasar charset
argumento para el constructor de conexión y tienen campos de la tabla no binarios (por ejemplo utf8_general_ci
). Pasar use_unicode
es inútil porque se establece en verdadero siempre que charset
tenga un valor.
MySQLdb respeta Descripción cursor tipos de campo, por lo que si tiene una columna DATETIME
en cursor los valores serán convertidos a Python datatime.datetime
casos, DECIMAL
a decimal.Decimal
y así sucesivamente, pero los valores binarios se representará como es, por cadenas de bytes. La mayoría de los decodificadores se definen en MySQLdb.converters
, y uno puede anularlos en base a instancia proporcionando el argumento conv
al constructor de conexión.
Pero los decodificadores unicode son una excepción aquí, lo que probablemente sea una falla de diseño. Son appended directly para convertidores de instancia de conexión en su constructor. Por lo tanto, solo es posible anularlos en instancia básica.
Solución temporal
Veamos el código de emisión.
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)
Muestra que b
campo se devuelve como una cadena de bytes en lugar de Unicode. Sin embargo, no es binario, MySQLdb.constants.FLAG.BINARY & cursor.description_flags[1]
(MySQLdb field flags). Parece un error en la biblioteca (abierto #90). Pero la razón por la que veo como MySQLdb.constants.FIELD_TYPE.LONG_BLOB
(cursor.description[1][1] == 251
, MySQLdb field types) simplemente no tiene un convertidor en absoluto.
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)
lo tanto mediante la manipulación de instancia de conexión converter
dict, es posible lograr un comportamiento de descodificación Unicode deseado.
Si desea sobrescribir el comportamiento, aquí se muestra cómo se ve una entrada dict para el posible campo de texto después del constructor.
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
. Esto significa que si un campo tiene bandera binaria será str
, de lo contrario se aplicará el decodificador Unicode. Por lo tanto, si desea intentar convertir valores binarios, puede mostrar la primera tupla.
Sí, estoy usando MySQLdb. Olvidé mencionar eso en mi publicación anterior. Probé configurar charset y use_unicode manualmente (aunque el primero parece implicar el último), pero el resultado es el mismo. También intenté configurar .decode ("utf-8") en la instrucción INSERT. Aún tiene el mismo formato ... – Raptor
¿Cuál es la codificación establecida en la columna de su base de datos? Pruebe utf8-bin. Es posible que esté transmitiendo los datos perfectamente, pero está escrito en alguna codificación que no incluye los caracteres que está utilizando. – marr75
La codificación era 'utf8_general_ci', intenté configurar la tabla y las columnas para' utf8_bin' sin ningún efecto. – Raptor