一、問題
這兩天在學習使用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。搞了半天,原來問題在這。
mysql> status--------------mysql Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1Connection id: 9Current database: web12306Current user: root@localhostSSL: Not in useCurrent pager: stdoutUsing outfile: ''Using delimiter: ;Server version: 5.1.73 Source distributionProtocol version: 10Connection: Localhost via UNIX socketServer characterset: utf8Db characterset: utf8Client characterset: latin1Conn. characterset: latin1UNIX socket: /var/lib/mysql/mysql.sock
3、解決問題
即然找到了,問題就在mysql 的my.cnf 上增加相關配置,并重啟mysql 服務:
# 進入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的例子:
#!/usr/bin/env python# -*- coding: UTF-8 -*-from sqlalchemy.orm import mapper, sessionmaker__author__ = 'tan9le' from sqlalchemy import create_engine, Table, Column, Integer, String, MetaDatafrom sqlalchemy.sql.expression import Castfrom sqlalchemy.ext.compiler import compilesfrom 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()#將創建的數據庫連接關聯到這個sessionSession.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()新聞熱點
疑難解答
圖片精選