Det visar sig att problemet är ganska besvärligt. Kort sagt, de flesta varianter och arter i MySQL-strängdatatyper a> map till en enskild datatyp i MySQL:s gränssnitt med en extra BINÄR flagga.
Alltså MySQL:s VARCHAR
, VARBINARY
, och en bokstavlig strängkarta till samma MySQLdb.constants.FIELD_TYPE.VAR_STRING
skriv in kolumntypsdefinitioner, men med ytterligare en MySQLdb.constants.FLAG.BINARY
flagga när typen är VARBINARY
eller en sträng sorterad med en *_bin
sammanställning.
Även om det finns en MySQLdb.constants.FIELD_TYPE.VARCHAR
typ, jag kunde inte ta reda på när den används. Som jag sa, MySQL VARCHAR
kolumner mappas till FIELD_TYPE.VAR_STRING
.
Lösningen blir ganska ömtålig om din applikation använder sanna binära strängar (till exempel lagrar du bilder och hämtar dem med samma anslutning som text), eftersom den förutsätter avkodning av alla binära strängar till unicode. Fast det fungerar.
Som officiella dokument står:
I praktiken kan verklig smärta i röven vara processen att skapa din egen omvandlarordbok. Men du kan importera standarden från MySQLdb.converters.conversions
och patcha det, eller till och med patcha det på en instans av Connection. Tricket är att ta bort en speciell omvandlare för en FLAG.BINARY
flagga och lägg till en avkodare för alla fall. Om du uttryckligen anger en charset
parameter för MySQLdb.connect
, tvingar den use_unicode=1
parameter, som lägger till avkodaren åt dig, men du kan göra det själv:
>>> con = MySQLdb.connect(**params)
>>> con.converter[FIELD_TYPE.VAR_STRING]
[(128, <type 'str'>), (None, <function string_decoder at 0x01FFA130>)]
>>> con.converter[FIELD_TYPE.VAR_STRING] = [(None, con.string_decoder)]
>>> c = con.cursor()
>>> c.execute("SELECT %s COLLATE utf8_bin", u'м')
1L
>>> c.fetchone()
(u'\u043c',)
Du kan förmodligen behöva göra samma hack för FIELD_TYPE.STRING
om det behövs.
En annan lösning är att skicka explicit use_unicode=0
till MySQLdb.connect
och gör alla avkodningar i din kod, men jag skulle inte göra det.
Hoppas det här kan vara användbart för någon.