sql >> Database >  >> RDS >> Mysql

Hoe zorg ik ervoor dat SQLAlchemy een unicode-weglatingsteken correct in een mySQL-tabel invoegt?

De foutmelding

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

lijkt erop te wijzen dat een of andere Python-taalcode probeert het teken \u2026 . te converteren in een Latin-1 (ISO8859-1) string, en het faalt. Niet verrassend, dat karakter is U+2026 HORIZONTAL ELLIPSIS , dat geen enkel equivalent teken heeft in ISO8859-1.

Je hebt het probleem opgelost door de zoekopdracht ?charset=utf8 . toe te voegen in uw SQLAlchemy-verbindingsaanroep:

import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table

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

De sectie Database-urls van de SQLAlchemy-documentatie vertelt ons dat een URL die begint met mysql geeft een MySQL-dialect aan, met behulp van de mysql-python chauffeur.

De volgende sectie, Aangepaste DBAPI connect() argumenten , vertelt ons dat queryargumenten worden doorgegeven aan de onderliggende DBAPI.

Dus, wat doet de mysql-python driver maken van een parameter {charset: 'utf8'} ? Sectie Functies en attributen van hun documentatie zegt over de charset attribuut "...Indien aanwezig, wordt de tekenset voor de verbinding gewijzigd in deze tekenset, als ze niet gelijk zijn."

Om erachter te komen wat de tekenset voor verbindingen betekent, gaan we naar 10.1.4. Verbindingstekensets en -sorteringen van de MySQL 5.6-referentiehandleiding. Om een ​​lang verhaal kort te maken:MySQL kan inkomende query's interpreteren als een andere codering dan de tekenset van de database en anders dan de codering van de geretourneerde queryresultaten.

Aangezien het foutbericht dat je hebt gerapporteerd eruitziet als een Python-foutbericht in plaats van een SQL-foutbericht, vermoed ik dat iets in SQLAlchemy of mysql-python de query probeert te converteren naar een standaard verbindingscodering van latin-1 voordat u het verzendt. Dit is wat de fout veroorzaakt. Echter, de zoekreeks ?charset=utf8 in uw connect() oproep verandert de verbindingscodering en de U+2026 HORIZONTAL ELLIPSIS kan doorkomen.

Bijwerken: je vraagt ​​​​ook:"Als ik de tekenset-optie verwijder en vervolgens de beschrijving codeer met .encode('cp1252'), gaat het prima. Hoe kan een weglatingsteken doorkomen met cp1252 maar niet met unicode?"

De codering cp1252 heeft een horizontaal weglatingsteken bij bytewaarde \x85 . Het is dus mogelijk om een ​​Unicode-string te coderen die U+2026 HORIZONTAL ELLIPSIS bevat in cp1252 zonder fouten.

Onthoud ook dat in Python Unicode-tekenreeksen en bytetekenreeksen twee verschillende gegevenstypen zijn. Het is redelijk om te speculeren dat MySQLdb een beleid heeft om alleen bytestrings via een SQL-verbinding te verzenden. Het zou dus een vraag die als een Unicode-tekenreeks is ontvangen, coderen in een bytetekenreeks, maar een vraag die als een bytetekenreeks wordt ontvangen, alleen laten. (Dit is speculatie, ik heb de broncode niet bekeken.)

In de traceback die je hebt gepost, tonen de laatste twee regels (het dichtst bij waar de fout zich voordoet) de methodenamen literal , gevolgd door unicode_literal . Dat ondersteunt de theorie dat MySQLdb de query die het ontvangt als een Unicode-tekenreeks codeert in een bytetekenreeks.

Wanneer u de querystring zelf codeert, omzeilt u het deel van MySQLdb dat deze codering anders doet. Houd er echter rekening mee dat als u de queryreeks anders codeert dan de MySQL-verbindingstekenset vereist, u een coderingsfout krijgt en dat uw tekst waarschijnlijk verkeerd wordt opgeslagen.



  1. SQL voor het ordenen van een alfanumerieke tekenreeks op het numerieke gedeelte

  2. Bestand versus database voor opslagefficiëntie in chat-app

  3. Hoe mysql JOIN te gebruiken zonder ON-voorwaarde?

  4. MySQL-update of hernoem een ​​sleutel in JSON