一、問題
這兩天在學習使用flask + SQLAlchemy 定製一個web查詢頁面的demo ,在測試時,發現查詢到的結果顯示亂碼 。這裡將解決方法記錄下。
二、解決思路
1、flask 程式上定位
flask的文件中提到可以通過設定 SQLALCHEMY_NATIVE_UNICODE 來禁止使用 SQLAlchemy 預設的 Unicode 編碼。有可能是SQLAlchemy預設的Unicode編碼不是UTF-8,抱著這樣的想法,在程式中指定了“SQLALCHEMY_NATIVE_UNICODE=False”,執行程式,報錯。
flask中還提到“use_native_unicode”為目標編碼來指定編碼方式,嘗試將“db = SQLAlchemy(app)”改為“db = SQLAlchemy(app, use_native_unicode=”utf8″)”。這回雖然沒報錯,但還是亂碼。
2、mysql 上定位
突然想到有可能是建表的時候,沒有指定字符集,使用的是資料庫預設的字符集的導致的。繼續找了一段時間的如何指定建表時使用字符集的方法,未果。
資料庫該不會使用的不是UTF-8吧?抱著這個想法,進入資料庫,輸入“status”,在輸出的資訊上顯示預設是latin-1。搞了半天,原來問題在這。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
mysql> status -------------- mysql Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1 Connection id: 9 Current database: web12306 Current user: root@localhost SSL: Not in use Current pager: stdout Using outfile: '' Using delimiter: ; Server version: 5.1.73 Source distribution Protocol version: 10 Connection: Localhost via UNIX socket Server characterset: utf8 Db characterset: utf8 Client characterset: latin1 Conn. characterset: latin1 UNIX socket: /var/lib/mysql/mysql.sock |
3、解決問題
即然找到了,問題就在mysql 的my.cnf 上增加相關配置,並重啟mysql 服務:
1 2 3 4 5 6 7 8 9 10 |
# 進入mysql的配置檔案目錄 cd /etc/mysql/ # 編輯my.cnf配置檔案 vim my.cnf # 在檔案中的[mysqld]下面增加一行內容 character_set_server = utf8 # 在[client]和[mysql]下面分別增加一行內容 default-character-set = utf8 # 儲存。然後重啟MySQL的服務,設定就生效了 service mysqld restart |
注:需要注意的是,之前已經存在的資料,在上面修改過後,通過mysql select查詢時會是亂碼,需要重新匯入。
PS:Python下SQLAlchemy真的是super好用,不太瞭解的童鞋可以嘗試一下下面這個MySQL的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
#!/usr/bin/env python # -*- coding: UTF-8 -*- from sqlalchemy.orm import mapper, sessionmaker __author__ = 'tan9le' from sqlalchemy import create_engine, Table, Column, Integer, String, MetaData from sqlalchemy.sql.expression import Cast from sqlalchemy.ext.compiler import compiles from sqlalchemy.dialects.mysql import BIGINT, BINARY, BIT, BLOB, BOOLEAN, CHAR, DATE, DATETIME, DECIMAL, DECIMAL, DOUBLE, ENUM, FLOAT, INTEGER, LONGBLOB, LONGTEXT, MEDIUMBLOB, MEDIUMINT, MEDIUMTEXT, NCHAR, NUMERIC, NVARCHAR, REAL, SET, SMALLINT, TEXT, TIME, TIMESTAMP, TINYBLOB, TINYINT, TINYTEXT, VARBINARY, VARCHAR, YEAR #表的屬性描述物件 metadata = MetaData() userTable = Table( "wzp_user",metadata, Column('user_id', Integer, primary_key=True), Column('user_name', VARCHAR(50), unique=True, nullable=False), Column('password', VARCHAR(40), nullable=True) ) #建立資料庫連線,MySQLdb連線方式 mysql_db = create_engine('mysql://使用者名稱:密碼@ip:port/dbname') #建立資料庫連線,使用 mysql-connector-python連線方式 #mysql_db = create_engine("mysql+mysqlconnector://使用者名稱:密碼@ip:port/dbname") #生成表 metadata.create_all(mysql_db) #建立一個對映類 class User(object): pass #把表對映到類 mapper(User, userTable) #建立了一個自定義了的 Session類 Session = sessionmaker() #將建立的資料庫連線關聯到這個session Session.configure(bind=mysql_db) session = Session() def main(): u = User() #給對映類新增以下必要的屬性,因為上面建立表指定這個欄位不能為空,且唯一 u.user_name='tan9le測試' #按照上面建立表的相關程式碼,這個欄位允許為空 u.password='123456' #在session中新增內容 session.add(u) #儲存資料 session.flush() #資料庫事務的提交,sisson自動過期而不需要關閉 session.commit() #query() 簡單的理解就是select() 的支援 ORM 的替代方法,可以接受任意組合的 class/column 表示式 query = session.query(User) #列出所有user print list(query) #根據主鍵顯示 print query.get(1) #類似於SQL的where,列印其中的第一個 print query.filter_by(user_name='tan9le測試').first() u = query.filter_by(user_name='tan9le測試').first() #修改其密碼欄位 u.password = '654321' #提交事務 session.commit() #列印會出現新密碼 print query.get(1).password #根據id欄位排序,列印其中的使用者名稱和密碼 for instance in session.query(User).order_by(User.user_id): print instance.user_name, instance.password #釋放資源 session.close() if __name__ == '__main__': main() |