1.请求解析
1.1 RequestParser
如果需要对请求数据进行序列化或反序列化操作,应该需要的对数据进行校验,我们可以通过RequestParser
来完成。使用步骤如下
1)parser = RequestParser()
2)parser .add_argument(参数名, 参数规则…)
3)args = parser.parse_args()
4)args.参数名
from flask import Flask
from flask_restful import Resource, Api
from flask_restful.reqparse import RequestParser
app = Flask(__name__)
api = Api(app)
class DemoResource(Resource):
def get(self):
parser = RequestParser()
parser.add_argument('name')
parser.add_argument('age')
# 默认会从查询字符串、post键值对、post-json数据进行参数提取
args = parser.parse_args()
print(args.name)
print(args.age)
return {'foo': "get"}
api.add_resource(DemoResource, '/')
if __name__ == '__main__':
app.run(debug=True)
1.2 解析参数
我们在添加参数规则的时候调用的是add_argument()
方法,该方法可以添加一些规则限制,常用的参数如下
- default:如果取不到该参数使用默认值
- required:是否要求必传
- location:提取参数的位置,比如说args/form/files/headers/cookies等
- type:类型转换(格式校验)
其中type参数的类型是校验传过来的参数是否符合某种类型,比如说是int,在某个范围,是日期类型等,也可以自定义,比如说手机号类型
from flask import Flask
from flask_restful import Resource, Api
from flask_restful.reqparse import RequestParser
# flask_restful内置的数据类型
from flask_restful.inputs import *
app = Flask(__name__)
api = Api(app)
def func1(value):
if re.match(r'^user:', value):
return value[5:] # 转换完, 还需要将结果返回
else:
raise ValueError('age参数格式错误') # 校验失败, 会将错误信息以json形式返回
class DemoResource(Resource):
def get(self):
parser = RequestParser()
# location=请求对象的属性,args form json cookies files
parser.add_argument("name", required=True, location="json", type=str) # 字符串类型
parser.add_argument("age", default=15, location="json", type=int_range(18, 55)) # 在18~25之间的整数
parser.add_argument("gender", required=True, location="json", type=boolean) # 布尔型
parser.add_argument("mobile", required=True, location="True", type=regex("r1[3-9]\d{9}$")) # 正则匹配
parser.add_argument('age', type=func1) # 自定义函数
ret = parser.parse_args()
print(ret.name)
print(ret["age"])
return {"foo": "get"}
def post(self):
return {"foo": "post"}
api.add_resource(DemoResource)
if __name__ == '__main__':
app.run(debug=True)
注意:经过type校验得到的类型不一定是python的数据类型,str类型的数据只要可以转换成int型即校验通过
2.序列化
flask-restful 通过 marshal函数 来完成序列化处理
1)序列化规则 = {字段名: 序列化类型}
2)序列化后的字典 = marshal(模型对象, 序列化规则)
方式1:使用marshal()函数
from flask import Flask
from flask_restful import Api, fields, Resource, marshal_with, marshal
app = Flask(__name__)
api = Api(app)
class Person(object):
def __init__(self):
self.name = "pan"
self.age = 18
self.height = 166.6
self.my_list = [30, 40, 50]
self.my_dict = {"gender": True}
user_dict = {
"name": fields.String(attribute='name'),
"age": fields.Integer(default=10),
"height": fields.Float,
"my_list": fields.List(fields.Integer),
"my_dict": fields.Nested({'gender': fields.Boolean})
}
class DemoResource(Resource):
def get(self):
user1 = Person()
# marshal函数可以按照指定的序列化规则将 模型对象 转为 字典
return marshal(user1, user_dict, envelope='data')
def post(self):
pass
api.add_resource(DemoResource, '/')
if __name__ == '__main__':
app.run(debug=True)
方式2:使用marshal_with()装饰器
from flask import Flask
...
class Person(object):
...
user_dict = {
...
}
class DemoResource(Resource):
method_decorators = {'post': [marshal_with(user_dict)]}
def get(self):
...
def post(self):
user2 = Person()
return user2
api.add_resource(DemoResource, '/')
if __name__ == '__main__':
app.run(debug=True)
方式3:自定义方法
from flask import Flask
...
class Person(object):
def __init__(self):
...
def to_dict(self):
return {
'name': self.name,
'age': self.age
}
class DemoResource(Resource):
method_decorators = {'post': [marshal_with(user_dict)]}
def get(self):
...
def post(self):
...
def put(self):
user3 = Person()
return user3.to_dict()
api.add_resource(DemoResource, '/')
if __name__ == '__main__':
app.run(debug=True)
3.自定义JSON
际开发中, 返回的JSON数据中除了包含基础数据, 往往还需要设置一些 统一的外层包装, 以便前端进行更好的解析处理。我们可以通过api.representation()
装饰器自定义返回数据
我们可以查看output_json()函数的源码大概知道整个执行过程,然后完全把该函数复制过来,进行自定义修改,再使用@api.representation('application/json')
即可达到目的
from json import dumps
from flask import Flask, current_app, make_response, Response
from flask_restful import Resource, Api
from six import PY3
app = Flask(__name__)
api = Api(app)
# 查看output_json()函数的源码
# import flask_restful.representations.json
@api.representation('application/json') # 指定响应形式对应的转换函数
def output_json(data: object, code: object, headers: object = None) -> object:
settings = current_app.config.get('RESTFUL_JSON', {})
if current_app.debug:
settings.setdefault('indent', 4)
settings.setdefault('sort_keys', not PY3)
# 添加json外层包装
if 'message' not in data: # 判断是否设置了自定义的错误信息
data = {
'message': 'ok',
'data': data
}
dumped = dumps(data, **settings) + "\n"
resp = make_response(dumped, code)
resp.headers.extend(headers or {})
return resp
class DemoResource(Resource):
def get(self):
return {'foo': "get"}
def post(self):
return {'message': 'parameter error: name', "data": None}
api.add_resource(DemoResource, '/')
if __name__ == '__main__':
app.run(debug=True)
提示: 因为直接把源码贴到视图函数里不太方便,我们可以把它写到某个文件里,需要它的地方再import到视图文件,然后把装饰器当函数使用
# 装饰器名(参数名)(被装饰函数名)
api.representation('application/json')(output_json)