Fejlmeddelelsen
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u2026'
in position 35: ordinal not in range(256)
synes at indikere, at en eller anden Python-sprogkode forsøger at konvertere tegnet \u2026
ind i en Latin-1 (ISO8859-1) streng, og den fejler. Ikke overraskende, den karakter er U+2026 HORIZONTAL ELLIPSE
, som ikke har et enkelt tilsvarende tegn i ISO8859-1.
Du løste problemet ved at tilføje forespørgslen ?charset=utf8
i dit SQLAlchemy-forbindelseskald:
import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table
db = create_engine('mysql://user:[email protected]/db?charset=utf8')
Sektionen Database-URL'er
i SQLAlchemy-dokumentationen fortæller os, at en URL, der begynder med mysql
angiver en MySQL-dialekt ved hjælp af mysql-python
chauffør.
Det følgende afsnit, Tilpasset DBAPI connect() argumenter , fortæller os, at forespørgselsargumenter sendes til den underliggende DBAPI.
Så hvad betyder mysql-python
driverfabrikat af en parameter {charset:'utf8'}
? Sektion Funktioner og attributter
i deres dokumentation siger om charset
attribut "...hvis tilstede, vil forbindelsestegnsættet blive ændret til dette tegnsæt, hvis de ikke er ens."
For at finde ud af, hvad forbindelsestegnsættet betyder, henvender vi os til 10.1.4. Forbindelseskaraktersæt og samlinger i MySQL 5.6 referencemanualen. For at gøre en lang historie kort, kan MySQL have fortolket indgående forespørgsler som en kodning, der er anderledes end databasens tegnsæt, og anderledes end kodningen af de returnerede forespørgselsresultater.
Da den fejlmeddelelse, du rapporterede, ligner en Python snarere end en SQL-fejlmeddelelse, vil jeg spekulere i, at noget i SQLAlchemy eller mysql-python forsøger at konvertere forespørgslen til en standardforbindelseskodning af latin-1
før du sender den. Det er det, der udløser fejlen. Forespørgselsstrengen ?charset=utf8
i din connect()
opkald ændrer forbindelseskodningen og U+2026 HORIZONTAL ELLIPSIS
er i stand til at komme igennem.
Opdatering: du spørger også, "hvis jeg fjerner charset-indstillingen og derefter koder beskrivelsen ved hjælp af .encode('cp1252'), vil den gå fint igennem. Hvordan kan en ellipse komme igennem med cp1252, men ikke unicode?"
kodningen cp1252
har
et vandret ellipsetegn ved byteværdien \x85
. Det er således muligt at kode en Unicode-streng indeholdende U+2026 HORIZONTAL ELLIPSIS
ind i cp1252 uden fejl.
Husk også, at i Python er Unicode-strenge og byte-strenge to forskellige datatyper. Det er rimeligt at spekulere i, at MySQLdb kan have en politik med kun at sende byte-strenge over en SQL-forbindelse. Det ville således kode en forespørgsel modtaget som en Unicode-streng til en byte-streng, men ville lade en forespørgsel modtaget som en byte-streng alene. (Dette er spekulation, jeg har ikke kigget på kildekoden.)
I den tilbagesporing, du postede, viser de sidste to linjer (tættest på, hvor fejlen opstår) metodenavnene literal
, efterfulgt af unicode_literal
. Det plejer at understøtte teorien om, at MySQLdb koder den forespørgsel, den modtager som en Unicode-streng, til en byte-streng.
Når du selv koder forespørgselsstrengen, omgår du den del af MySQLdb, der gør denne kodning anderledes. Bemærk dog, at hvis du koder forespørgselsstrengen anderledes end MySQL-forbindelsens tegnsæt kalder på, vil du have en kodningsuoverensstemmelse, og din tekst vil sandsynligvis blive gemt forkert.