Python的Flask框架中SQLAlchemy使用时的乱码问题解决
一、问题
这两天在学习使用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 -------------- mysqlVer14.14Distrib5.1.73,forredhat-linux-gnu(x86_64)usingreadline5.1 Connectionid:9 Currentdatabase:web12306 Currentuser:root@localhost SSL:Notinuse Currentpager:stdout Usingoutfile:'' Usingdelimiter:; Serverversion:5.1.73Sourcedistribution Protocolversion:10 Connection:LocalhostviaUNIXsocket Servercharacterset:utf8 Dbcharacterset:utf8 Clientcharacterset:latin1 Conn.characterset:latin1 UNIXsocket:/var/lib/mysql/mysql.sock
3、解决问题
即然找到了,问题就在mysql的my.cnf上增加相关配置,并重启mysql服务:
#进入mysql的配置文件目录 cd/etc/mysql/ #编辑my.cnf配置文件 vimmy.cnf #在文件中的[mysqld]下面增加一行内容 character_set_server=utf8 #在[client]和[mysql]下面分别增加一行内容 default-character-set=utf8 #保存。然后重启MySQL的服务,设置就生效了 servicemysqldrestart
注:需要注意的是,之前已经存在的数据,在上面修改过后,通过mysqlselect查询时会是乱码,需要重新导入。
PS:Python下SQLAlchemy真的是super好用,不太了解的童鞋可以尝试一下下面这个MySQL的例子:
#!/usr/bin/envpython
#-*-coding:UTF-8-*-
fromsqlalchemy.ormimportmapper,sessionmaker
__author__='tan9le'
fromsqlalchemyimportcreate_engine,Table,Column,Integer,String,MetaData
fromsqlalchemy.sql.expressionimportCast
fromsqlalchemy.ext.compilerimportcompiles
fromsqlalchemy.dialects.mysqlimport\
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)
#创建一个映射类
classUser(object):
pass
#把表映射到类
mapper(User,userTable)
#创建了一个自定义了的Session类
Session=sessionmaker()
#将创建的数据库连接关联到这个session
Session.configure(bind=mysql_db)
session=Session()
defmain():
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
printlist(query)
#根据主键显示
printquery.get(1)
#类似于SQL的where,打印其中的第一个
printquery.filter_by(user_name='tan9le测试').first()
u=query.filter_by(user_name='tan9le测试').first()
#修改其密码字段
u.password='654321'
#提交事务
session.commit()
#打印会出现新密码
printquery.get(1).password
#根据id字段排序,打印其中的用户名和密码
forinstanceinsession.query(User).order_by(User.user_id):
printinstance.user_name,instance.password
#释放资源
session.close()
if__name__=='__main__':
main()