一、问题
这两天在学习使用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
79
80
81
82
|
#!/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()
|