sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo hago para que SQLAlchemy inserte correctamente puntos suspensivos Unicode en una tabla mySQL?

El mensaje de error

UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026' 
in position 35: ordinal not in range(256)

parece indicar que algún código del lenguaje Python está intentando convertir el carácter \u2026 en una cadena Latin-1 (ISO8859-1), y está fallando. No sorprende, ese carácter es U+2026 HORIZONTAL ELLIPSIS , que no tiene un único carácter equivalente en ISO8859-1.

Solucionaste el problema agregando la consulta ?charset=utf8 en su llamada de conexión SQLAlchemy:

import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table

db = create_engine('mysql://user:[email protected]/db?charset=utf8')

La sección URL de base de datos de la documentación de SQLAlchemy nos dice que una URL que comienza con mysql indica un dialecto MySQL, usando mysql-python conductor.

La siguiente sección, DBAPI personalizado argumentos connect() , nos dice que los argumentos de consulta se pasan al DBAPI subyacente.

Entonces, ¿qué significa mysql-python controlador marca de un parámetro {charset: 'utf8'} ? Sección Funciones y atributos de su documentación dice del charset atributo "...Si está presente, el conjunto de caracteres de conexión se cambiará a este conjunto de caracteres, si no son iguales".

Para averiguar qué significa el conjunto de caracteres de conexión, recurrimos a 10.1.4. Intercalaciones y conjuntos de caracteres de conexión del manual de referencia de MySQL 5.6. Para resumir, MySQL puede haber interpretado las consultas entrantes como una codificación diferente al conjunto de caracteres de la base de datos y diferente a la codificación de los resultados de la consulta devuelta.

Dado que el mensaje de error que informó parece un Python en lugar de un mensaje de error de SQL, especularé que algo en SQLAlchemy o mysql-python está intentando convertir la consulta a una codificación de conexión predeterminada de latin-1 antes de enviarlo. Esto es lo que desencadena el error. Sin embargo, la cadena de consulta ?charset=utf8 en tu connect() llamada cambia la codificación de la conexión y U+2026 HORIZONTAL ELLIPSIS es capaz de pasar.

Actualización: también pregunta, "si elimino la opción de juego de caracteres y luego codifico la descripción usando .encode('cp1252') funcionará bien. ¿Cómo es que una elipsis puede pasar con cp1252 pero no con Unicode?"

La codificación cp1252 tiene un carácter de puntos suspensivos horizontales en el valor de byte \x85 . Por lo tanto, es posible codificar una cadena Unicode que contenga U+2026 HORIZONTAL ELLIPSIS en cp1252 sin error.

Recuerde también que en Python, las cadenas Unicode y las cadenas de bytes son dos tipos de datos diferentes. Es razonable especular que MySQLdb podría tener una política de enviar solo cadenas de bytes a través de una conexión SQL. Por lo tanto, codificaría una consulta recibida como una cadena Unicode en una cadena de bytes, pero dejaría una consulta recibida como una cadena de bytes sola. (Esto es especulación, no he mirado el código fuente).

En el rastreo que publicaste, las últimas dos líneas (las más cercanas a donde ocurrió el error) muestran los nombres de los métodos literal , seguido de unicode_literal . Eso tiende a respaldar la teoría de que MySQLdb está codificando la consulta que recibe como una cadena Unicode en una cadena de bytes.

Cuando codifica la cadena de consulta usted mismo, omite la parte de MySQLdb que hace esta codificación de manera diferente. Tenga en cuenta, sin embargo, que si codifica la cadena de consulta de manera diferente a la que requiere el juego de caracteres de conexión de MySQL, tendrá una discrepancia de codificación y es probable que su texto se almacene de forma incorrecta.