Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Wie bringe ich SQLAlchemy dazu, eine Unicode-Auslassung korrekt in eine mySQL-Tabelle einzufügen?

Die Fehlermeldung

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

scheint anzuzeigen, dass irgendein Python-Sprachcode versucht, das Zeichen \u2026 zu konvertieren in eine Latin-1 (ISO8859-1) Zeichenfolge, und es schlägt fehl. Nicht überraschend, dieses Zeichen ist U+2026 HORIZONTAL ELLIPSIS , das in ISO8859-1 kein einziges äquivalentes Zeichen hat.

Sie haben das Problem behoben, indem Sie die Abfrage ?charset=utf8 hinzugefügt haben in Ihrem SQLAlchemy-Verbindungsaufruf:

import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table

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

Der Abschnitt Datenbank-URLs der SQLAlchemy-Dokumentation sagt uns, dass eine URL, die mit mysql beginnt gibt einen MySQL-Dialekt an, der den mysql-python verwendet Fahrer.

Der folgende Abschnitt, Benutzerdefinierte DBAPI connect()-Argumente , teilt uns mit, dass Abfrageargumente an die zugrunde liegende DBAPI übergeben werden.

Also, was macht der mysql-python Treibermarke eines Parameters {charset:'utf8'} ? Abschnitt Funktionen und Attribute ihrer Dokumentation sagt von charset Attribut "...Falls vorhanden, wird der Verbindungszeichensatz auf diesen Zeichensatz geändert, wenn sie nicht gleich sind."

Um herauszufinden, was der Verbindungszeichensatz bedeutet, wenden wir uns an 10.1.4. Verbindungszeichensätze und Sortierungen des MySQL 5.6-Referenzhandbuchs. Um es kurz zu machen, MySQL kann eingehende Abfragen als eine Codierung interpretieren lassen, die sich vom Zeichensatz der Datenbank und von der Codierung der zurückgegebenen Abfrageergebnisse unterscheidet.

Da die von Ihnen gemeldete Fehlermeldung eher wie eine Python- als eine SQL-Fehlermeldung aussieht, spekuliere ich, dass etwas in SQLAlchemy oder mysql-python versucht, die Abfrage in eine Standardverbindungscodierung von latin-1 bevor Sie es senden. Das löst den Fehler aus. Allerdings ist die Abfragezeichenfolge ?charset=utf8 in Ihrem connect() call ändert die Verbindungskodierung und die U+2026 HORIZONTAL ELLIPSIS durchkommen kann.

Aktualisierung: Sie fragen auch:"Wenn ich die Zeichensatzoption entferne und dann die Beschreibung mit .encode('cp1252') codiere, wird sie problemlos durchgehen. Wie kann eine Ellipse mit cp1252, aber nicht mit Unicode durchkommen?"

Die Codierung cp1252 hat ein horizontales Auslassungszeichen beim Bytewert \x85 . Somit ist es möglich, einen Unicode-String zu kodieren, der U+2026 HORIZONTAL ELLIPSIS enthält in cp1252 ohne Fehler.

Denken Sie auch daran, dass Unicode-Strings und Byte-Strings in Python zwei verschiedene Datentypen sind. Es ist vernünftig zu spekulieren, dass MySQLdb die Richtlinie hat, nur Byte-Strings über eine SQL-Verbindung zu senden. Somit würde es eine als Unicode-String empfangene Abfrage in einen Byte-String codieren, aber eine als Byte-String empfangene Abfrage allein lassen. (Das ist Spekulation, ich habe mir den Quellcode nicht angesehen.)

In dem von Ihnen geposteten Traceback zeigen die letzten beiden Zeilen (am nächsten an der Stelle, an der der Fehler auftritt) die Methodennamen literal , gefolgt von unicode_literal . Das stützt tendenziell die Theorie, dass MySQLdb die empfangene Abfrage als Unicode-String in einen Byte-String kodiert.

Wenn Sie die Abfragezeichenfolge selbst codieren, umgehen Sie den Teil von MySQLdb, der diese Codierung anders macht. Beachten Sie jedoch, dass, wenn Sie die Abfragezeichenfolge anders codieren, als der MySQL-Verbindungszeichensatz fordert, Sie eine Codierungsabweichung haben und Ihr Text wahrscheinlich falsch gespeichert wird.