2012-03-01 71 views
2

爲了某些目的,我必須在數據庫中將字段歸類從utf8_unicode_ci更改爲utf8_bin。事實證明,這種變化導致了python數據類型的變化。mysql-python整理問題:如何強制unicode數據類型?

問題是如何強制mysql-python將unicode對象返回給python

這裏是一個示例,演示問題(顯式的字符集力量use_unicode = 1):

>>> con = MySQLdb.connect(..., charset='utf8') 
>>> c = c.cursor() 
>>> c.execute('SELECT %s COLLATE utf8_bin', u'м') 
1L 
>>> c.fetchone() 
('\xd0\xbc',) 
>>> c.description 
(("'\xd0\xbc' COLLATE utf8_bin", 253, 2, 3, 3, 31, 0),) 


>>> c.execute('SELECT %s COLLATE utf8_unicode_ci', u'м') 
1L 
>>> c.fetchone() 
(u'\u043c',) 
>>> c.description 
(("'\xd0\xbc' COLLATE utf8_unicode_ci", 253, 2, 3, 3, 31, 0),) 

在我的數據庫中的字段VARCHAR類型的,但變化後,他們表現得像二進制文件,是不是有什麼我想要。

+0

'SET NAMES utf8'? – Robus 2012-03-01 19:14:46

+0

@Robus,'charset = utf8'完全一樣 – newtover 2012-03-01 19:18:40

+1

不確定,因此爲什麼我只發佈它作爲評論:)我相信實際上'解碼'變量python-side可能需要更少的努力比與messing – Robus 2012-03-01 19:21:08

回答

2

事實證明,問題相當尷尬。簡而言之,MySQL string datatypes中的大多數變體和物種都映射到MySQL接口中的單個數據類型,並帶有一個額外的BINARY標誌。

因此,MySQL的VARCHARVARBINARY,和一個字符串地圖在柱類型定義相同MySQLdb.constants.FIELD_TYPE.VAR_STRING類型,但是具有附加的標記MySQLdb.constants.FLAG.BINARY當類型是VARBINARY或具有*_bin覈對整理的字符串。

即使有MySQLdb.constants.FIELD_TYPE.VARCHAR類型,我也未能發現它何時被使用。正如我所說,MySQL VARCHAR列映射到FIELD_TYPE.VAR_STRING

如果您的應用程序使用真正的二進制字符串(例如,您存儲圖像並使用與文本相同的連接來獲取它們),解決方案變得相當脆弱,因爲它假定將所有二進制字符串解碼爲unicode。雖然,它的作品。

官方docs狀態:

因爲MySQL將返回所有數據串並期望用戶自行將其轉換。這將是一個真正的痛苦,但事實上,_mysql可以爲你做到這一點。 (MySQLdb確實爲你做了這些。)要完成自動類型轉換,您需要創建一個類型轉換器字典,並將其作爲關鍵字參數傳遞給connect()。

實際上,真正的屁股疼痛可能是構建自己的轉換器字典的過程。但是您可以從MySQLdb.converters.conversions導入默認的並修補它,甚至可以將它修補到連接的一個實例上。訣竅是刪除FLAG.BINARY標誌的特殊轉換器,併爲所有情況添加解碼器。如果明確指定charset參數MySQLdb.connect,它迫使use_unicode=1參數,它增加了解碼器爲你,但你可以自己做:

>>> 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',) 

你也許可能需要做出同樣的黑客對FIELD_TYPE.STRING如果需要的話。

另一種解決方案是將明確的use_unicode=0轉換爲MySQLdb.connect並在代碼中進行所有解碼,但我不會。

希望,這可能對某人有用。

1

這是從低級別使用Mysql-Python的大量改變,但我認爲更好的想法是使用類似sqlalchemy而不是直接使用db-api,然後可以使用例如sqlalchemy。類型.Unicode並知道它正在做的事情需要unicode支持db-api

在你跳過我不直接回答問題之前,考慮一下:mysql-python aka MySQLdb只是幾個db-api之一對於MySQL。 MySQLdb可能會繼續受到新版本的支持,但有些情況下(例如遷移到python 3x,或者無法安裝二進制模塊的主機)可能會迫使您在將來使用其他內容,例如如oursqlmyconnpy。製作sqlalchemy的人經歷了很多努力來支持多個db-api,並且在mysql-python的情況下,甚至在過去也處理過嚴重的錯誤。對於sqlalchemy,更改爲不同的db-api將與更改連接URL一樣簡單,並且可以確保按照您的預期處理數據類型強制轉換上的任何操作。

也就是說,要利用它,你需要根據sqlalchemy的模式定義你的表並使用它們的查詢API,但是你會得到很多。