Mysql
 sql >> Database >  >> RDS >> Mysql

Come faccio a fare in modo che SQLAlchemy inserisca correttamente i puntini di sospensione Unicode in una tabella MySQL?

Il messaggio di errore

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

sembra indicare che alcuni codici del linguaggio Python stanno cercando di convertire il carattere \u2026 in una stringa Latin-1 (ISO8859-1) e non riesce. Non sorprende che quel carattere sia U+2026 HORIZONTAL ELLIPSIS , che non ha un singolo carattere equivalente in ISO8859-1.

Hai risolto il problema aggiungendo la query ?charset=utf8 nella tua chiamata di connessione SQLAlchemy:

import sqlalchemy
from sqlalchemy import create_engine, MetaData, Table

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

La sezione Url database della documentazione di SQLAlchemy ci dice che un URL che inizia con mysql indica un dialetto MySQL, usando mysql-python conducente.

La sezione seguente, DBAPI personalizzato connect() argomenti , indica che gli argomenti della query vengono passati al DBAPI sottostante.

Quindi, cosa significa mysql-python driver make di un parametro {charset: 'utf8'} ? Sezione Funzioni e attributi della loro documentazione dice del charset attributo "...Se presente, il set di caratteri di connessione verrà modificato in questo set di caratteri, se non sono uguali."

Per scoprire cosa significa il set di caratteri di connessione, ci rivolgiamo a 10.1.4. Set di caratteri di connessione e regole di confronto del manuale di riferimento di MySQL 5.6. Per farla breve, MySQL può interpretare le query in arrivo come una codifica diversa dal set di caratteri del database e diversa dalla codifica dei risultati della query restituiti.

Poiché il messaggio di errore che hai segnalato sembra un messaggio di errore Python piuttosto che SQL, ipotizzerò che qualcosa in SQLAlchemy o mysql-python stia tentando di convertire la query in una codifica di connessione predefinita di latin-1 prima di inviarlo. Questo è ciò che provoca l'errore. Tuttavia, la stringa di query ?charset=utf8 nel tuo connect() call cambia la codifica della connessione e la U+2026 HORIZONTAL ELLIPSIS riesce a passare.

Aggiornamento: chiedi anche "se rimuovo l'opzione charset e poi codifico la descrizione usando .encode('cp1252') andrà bene. Come è possibile che i puntini di sospensione siano in grado di superare cp1252 ma non unicode?"

La codifica cp1252 ha un punto di sospensione orizzontale al valore byte \x85 . In questo modo è possibile codificare una stringa Unicode contenente U+2026 HORIZONTAL ELLIPSIS in cp1252 senza errori.

Ricorda anche che in Python, le stringhe Unicode e le stringhe di byte sono due tipi di dati diversi. È ragionevole ipotizzare che MySQLdb possa avere una politica di invio di sole stringhe di byte su una connessione SQL. Pertanto codificherebbe una query ricevuta come stringa Unicode in una stringa di byte, ma lascerebbe una query ricevuta come stringa di byte da sola. (Questa è una speculazione, non ho guardato il codice sorgente.)

Nel traceback che hai postato, le ultime due righe (più vicine a dove si è verificato l'errore) mostrano i nomi dei metodi literal , seguito da unicode_literal . Ciò tende a supportare la teoria secondo cui MySQLdb sta codificando la query che riceve come stringa Unicode in una stringa di byte.

Quando codifichi tu stesso la stringa di query, salti la parte di MySQLdb che esegue questa codifica in modo diverso. Nota, tuttavia, che se codifichi la stringa di query in modo diverso da quello richiesto dal set di caratteri di connessione MySQL, avrai una mancata corrispondenza della codifica e probabilmente il tuo testo verrà archiviato in modo errato.