Python中flask-sqlalchemy查询Oracle数据库时,query.all()返回结果出现编码问题如何解决?

我初学 python,打算照着网上的例程,用 flask 搭一个笔记网站练手,因为想着尽量贴近公司现有的基础资源,所以数据库没有照例程的用 mongoDB,而是直接连公司的 oracle 数据库,悲催的是这个库编码已经是 ZHS16GBK,不可能更改,而且也会是以后绕不过的一个坑,所以还是得将这个骨头啃下来。   现在的困难是,我能成功建表、写入数据,在构造 class 的时候,我增加了 toGBK()方法,将几个字段都转码,这样写进去的中文也是正常格式了。我还写了个 toUTF8()方法,准备照样子将查询出来的结果转为 UTF-8,可惜在 Note.query.all()这一步查询时就报错了,错误信息是: UnicodeDecodeError: 'utf8' codec can't decode byte 0xbf in position 0: invalid start byte

我直接自己写 sql 去查,都能成功转码,不懂为啥用了 query.all()就出错了。下面是我测试环境和两个相关文件代码,希望大家帮忙。

先列一下我这边的版本:

服务器:64 位 centos 7.3.1611
系统编码环境: 
    LANG=en_US.UTF-8
    NLS_LANG='SIMPLIFIED CHINESE_CHINA.ZHS16GBK'

Python 2.7.5

cx-Oracle==5.3 decorator==3.4.0 ez-setup==0.9 Flask==0.12.2 Flask-Script==2.0.5 Flask-SQLAlchemy==2.2 SQLAlchemy==1.1.13

oracle 数据库和客户端的版本都是 11.2.0.4

app/models.py 文件

from app import db
import datetime

class Note(db.Model): tablename = ‘WKNT_NOTES’ id_seq = db.Sequence(‘WKNT_NOTES_ID_SEQ’)

id       = db.Column(db.Integer, id_seq, primary_key=True)
created  = db.Column(db.DateTime, default=datetime.datetime.now())
category = db.Column(db.String(60))
opt      = db.Column(db.String(60))
content  = db.Column(db.String(2000))
name     = db.Column(db.String(60))

def __init__(self, category, opt, content, name):
	self.category = category
	self.opt      = opt
	self.content  = content
	self.name     = name

def __repr__(self):
	return '<ID %r>' % self.id

def toGBK(self):
	self.category = self.category.decode("utf-8").encode("GBK")
	self.opt      = self.opt.decode("utf-8").encode("GBK")
	self.content  = self.content.decode("utf-8").encode("GBK")
	self.name     = self.name.decode("utf-8").encode("GBK")
	return self

def toUTF8(self):
	self.category = self.category.decode("GBK").encode("utf-8")
	self.opt      = self.opt.decode("GBK").encode("utf-8")
	self.content  = self.content.decode("GBK").encode("utf-8")
	self.name     = self.name.decode("GBK").encode("utf-8")
	return self

manage.py 文件

# -*- coding: utf-8 -*-

from flask_script import Manager, Server from app import *

manager = Manager(app)

manager.add_command(“runserver”, Server(host=‘0.0.0.0’,port=80, use_debugger=True))

@manager.command def save_note(): note = models.Note( content=‘开张大吉’, name=‘daviswei’, opt=‘create’, category=‘网络’) note.toGBK() db.create_all() db.session.add(note) db.session.commit()

@manager.command def read_note(): notes = models.Note.query.all() for n in notes: n.toUTF8() print(n)

@manager.command def read_direct(): sql = ‘select * from wknt_notes’ for notes in db.engine.execute(sql): print notes.content.decode(“GBK”).encode(“utf-8”)

if name == ‘main’: manager.run()


Python中flask-sqlalchemy查询Oracle数据库时,query.all()返回结果出现编码问题如何解决?

3 回复

遇到Oracle编码问题,通常是因为数据库字符集与Python环境不匹配。试试在连接字符串里指定编码,或者用cx_Oracleencoding参数。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import cx_Oracle

app = Flask(__name__)
# 关键在这里:在连接URI里加上编码参数
app.config['SQLALCHEMY_DATABASE_URI'] = 'oracle+cx_oracle://user:password@host:port/service_name?encoding=UTF-8&nencoding=UTF-8'
# 或者用这个,效果差不多
# app.config['SQLALCHEMY_DATABASE_URI'] = 'oracle://user:password@host:port/service_name?charset=utf8'

db = SQLAlchemy(app)

class YourModel(db.Model):
    __tablename__ = 'your_table'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100))

# 查询
results = YourModel.query.all()
for r in results:
    print(r.name)

如果还不行,检查下系统环境变量NLS_LANG,设成AMERICAN_AMERICA.AL32UTF8试试。有时候是cx_Oracle本身的问题,确保你用的是最新版。

总结:优先在连接字符串里指定UTF-8编码。


自己顶起来,是不是该考虑每个 class 自己写个查询方法了。。。可是这样的话,我还想用 filter 怎么办

想通了,进出都不转码,库里面记录是乱码就乱码吧

回到顶部