# app.configurations
app.config['SECURITY_KEY'] = 'you will never guess'
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URI']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['JSON_SORT_KEYS'] = False
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'user'
USER_ID = db.Column(db.Integer, primary_key=True)
USERNAME = db.Column(db.String(20))
CREATED_BY = db.Column(db.String(20))
CREATED_DATE = db.Column(db.Date)
def user_to_dict(user):
return OrderedDict(
USER_ID = user.USER_ID,
USERNAME = user.USERNAME,
CREATED_BY = user.CREATED_BY,
CREATED_DATE = user.CREATED_DATE
@app.route('/users')
def list_users():
users = User.query.all()
return jsonify(list(map(user_to_dict, users)))
@app.route('/users/
')
def find_user(userid):
user = User.query.get(userid)
return jsonify(user_to_dict(user))
if __name__ == "__main__":
app.run(debug=True)
在本例中,
user_to_dict()
函数实现了将 user 对象转换为 dict,但这种写法是硬编码的,有多少个 Model 就要写多少个函数,所以,我们接下来考虑如何实现通用的代码。
对于 User 的实例,可以用
__dict__
特殊属性获取实例的字段,为了通用化,将代码放在一个基类中:
class EntityBase(object):
def to_json(self):
fields = self.__dict__
if "_sa_instance_state" in fields:
del fields["_sa_instance_state"]
return fields
然后在 Model 中通过多重继承,让 model 继承 EntitiBase
类,这样就不用改变每个 model 类的代码。为了方便叙述和学习,也给出第二种方法的完整代码:
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
import os
from collections import OrderedDict
app = Flask(__name__)
# application configurations
app.config['SECURITY_KEY'] = 'you will never guess'
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URI']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['JSON_SORT_KEYS'] = False
db = SQLAlchemy(app)
class EntityBase(object):
def to_json(self):
fields = self.__dict__
if "_sa_instance_state" in fields:
del fields["_sa_instance_state"]
return fields
class User(db.Model, EntityBase):
__tablename__ = 'user'
USER_ID = db.Column(db.Integer, primary_key=True)
USERNAME = db.Column(db.String(20))
CREATED_BY = db.Column(db.String(20))
CREATED_DATE = db.Column(db.Date)
@app.route('/users')
def list_users():
users = User.query.all()
users_output = []
for user in users:
users_output.append(user.to_json())
return jsonify(users_output)
@app.route('/users/<userid>')
def find_user(userid):
user = User.query.get(userid)
return jsonify(user.to_json())
if __name__ == "__main__":
app.run(debug=True)
如果有多个表,并且有关联,以上方法需要更多的手工代码。比较好的方法是使用第三方模块:Flask-Marshmallow,这个也是我想推荐的方法。通过 pip 安装 Flask-Marshmallow 模块后,我们需要定义一个 UserSchema 类,并且确定 UserSchema 对应到 User,如下面的代码:
from flask_marshmallow import Marshmallow
ma = Marshmallow(app)
class UserSchema(ma.ModelSchema):
class Meta:
model = User
然后在路由中,可以方便的通过 dump()
方法转换为 dict。
@app.route('/users')
def list_users():
users = User.query.all()
user_schema = UserSchema(many=True)
user_data = user_schema.dump(users).data
return jsonify(user_data)
@app.route('/users/<userid>')
def find_user(userid):
user = User.query.get(userid)
user_schema = UserSchema()
user_data = user_schema.dump(user).data
return jsonify(user_data)
完整代码如下:
from flask import Flask, jsonify
from flask_marshmallow import Marshmallow
from flask_sqlalchemy import SQLAlchemy
import os
app = Flask(__name__)
# application configurations
app.config['SECURITY_KEY'] = 'you will never guess'
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URI']
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['JSON_SORT_KEYS'] = False
db = SQLAlchemy(app)
ma = Marshmallow(app)
class User(db.Model):
__tablename__ = 'user'
USER_ID = db.Column(db.Integer, primary_key=True)
USERNAME = db.Column(db.String(20), nullable=False)
CREATED_BY = db.Column(db.String(20), nullable=False)
CREATED_DATE = db.Column(db.Date, nullable=False)
class UserSchema(ma.ModelSchema):
class Meta:
model = User
@app.route('/users')
def list_users():
users = User.query.all()
user_schema = UserSchema(many=True)
user_data = user_schema.dump(users).data
return jsonify(user_data)
@app.route('/users/<userid>')
def find_user(userid):
user = User.query.get(userid)
user_schema = UserSchema()
user_data = user_schema.dump(user).data
return jsonify(user_data)
if __name__ == "__main__":
app.run(debug=True)
源码放在 github 上。