2012-05-30 13 views
18

Ho una query SQL che ho eseguito come questo con un motore SQLAlchemy:Il risultato di SQLAlchemy per la colonna UTF-8 è di tipo "str", perché?

result = engine.execute('SELECT utf_8_field FROM table') 

Il database è MySQL e il tipo di colonna è TEXT con codifica UTF-8. Il tipo di utf_8_field restituito è "str", anche se imposto l'opzione convert_unicode = True durante la creazione del motore. Quello che succede ora è che se ho un carattere come 'é' nella mia stringa (che non è in ASCII a 7 bit, ma è nel set ASCII esteso), ottengo un errore UnicodeDecodeError quando cerco di eseguire questo:

utf_8_field.encode("utf-8") 

l'errore esatto è:

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe9 in position 1: ordinal not in range(128) 

Quando si cerca in questo, ho trovato che str.encode non supportano il carattere ASCII esteso set! Lo trovo davvero strano, ma questa è un'altra domanda.

Quello che non capisco è perché SQLAlchemy non mi sta dando una stringa unicode. In precedenza utilizzavo DB-API e funzionava perfettamente. Inoltre non ho ancora oggetti SQLAlchemy per le mie tabelle, ecco perché sto usando un comando execute.

Qualche idea?

risposta

33

Se si desidera che i dati convertiti automaticamente, si dovrebbe specify the charset quando si crea il motore:

create_engine('mysql+mysqldb:///mydb?charset=utf8') 

Impostazione use_unicode da solo non vi dirà che sqlalchemy charset da utilizzare.

+0

Grazie, ora converte il mio campo utf-8 in stringhe python unicode. – Faelenor

+1

In base al messaggio di errore, il primo byte non ASCII nel "campo utf-8" è '0xe9'. Ciò indica che è ** NON ** codificato in UTF-8 ... molto più probabile che sia 'cp1252'. –

+0

@JohnMachin - sì, perché se non si specifica un set di caratteri durante la creazione del motore, mysqldb sembra essere impostato su latin1. L'impostazione del set di caratteri indica sia al db ant che al client di utilizzare la codifica di trasferimento corretta e quindi corregge il problema. – mata

2

convertire da un UTF-8 bytestring a un oggetto unicode, è necessario decodifica:

utf_8_field.decode('utf8') 

Inoltre, durante l'esecuzione di un grezzo SELECT attraverso .execute, SQLAlchemy non ha metadati per capire che la vostra la query restituisce i dati utf-8, quindi non converte queste informazioni in unicode per te.

In altre parole, convert_unicode funziona solo se si utilizza l'API di espressione SQL di SQLAlchemy o la funzionalità ORM.

MODIFICA: come indicato, i dati non sono nemmeno codificati in UTF-8; 0xe9 in UTF-8 indica un carattere compreso tra \u9000 e \u9fff, che sono ideogrammi unificati CJK mentre si diceva che era un carattere latin-1, il cui codice UTF-8 iniziava con 0xc3. Questo è probabilmente ISO-8859-1 (latin-1) o simile, invece:

>>> u'é'.encode('ISO-8859-1') 
'\xe9' 

La conclusione quindi è quello di raccontare SQLAlchemy per connettersi con un altro set di caratteri, utilizzando il parametro charset=utf8, come sottolineato da @mata.

+0

La riga di codifica ('utf-8') era presente in precedenza, quando si utilizza DB-API. Immagino che fosse perché il database ha restituito la stringa convertita in unicode e volevamo tornare a utf-8. – Faelenor

+0

-1 Non ha dati codificati in UTF-8. Leggi il suo messaggio di errore. –

+0

@JohnMachin: Il suo messaggio di errore afferma che il codec predefinito utilizzato per decodificare prima il suo bytestring ('ascii') non può gestire UTF-8. Questo perché codificare un bytestring richiede prima che venga decodificato in Unicode, che è ciò che non è riuscito. –

Problemi correlati