目录
起步
Flask-RESTful是用于快速构建REST API的Flask扩展。
1 安装
pip install flask-restful
2 Hello World
# 创建Api类对象 收集类视图的注册信息 在flask类代表不同的资源 不同的方法对应到不同的请求方式
api对象收集路径信息跟路由绑定的
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class HelloWorldResource(Resource):
def get(self):
return {'hello': 'world'}
def post(self):
return {'msg': 'post hello world'}
api.add_resource(HelloWorldResource, '/')
# 此处启动对于1.0之后的Flask可有可无
if __name__ == '__main__':
app.run(debug=True)
注:flask_restful中返回的字典类型 可以自动转化为json
关于视图
1 为路由起名
通过endpoint参数为路由起别名
api.add_resource(HelloWorldResource, '/', endpoint='HelloWorld')
2 蓝图中使用
from flask import Flask,Blueprint
from flask_restful import Resource,Api
app=Flask(__name__)
# 1 创建蓝图对象
bp=Blueprint("bp",__name__)
# 创建Api类对象 收集类视图的注册信息 在flask类代表不同的资源 不同的方法对应到不同的请求方式
# api=Api(app)
# 2.创建Api扩展的对象时 绑定蓝图对象
api=Api(bp)
class HelloWorldResource(Resource):
def get(self):
return {"hello":"world"}
def post(self):
return {"mes":"return post hello world"}
# api.add_resource(HelloWorldResource,'/')
# 3 收集类视图的注册信息 交给了蓝图bp
api.add_resource(HelloWorldResource,'/')
# 4. 将蓝图对象注册到全局的flask里面
app.register_blueprint(bp)
3 装饰器
使用method_decorators
添加装饰器
- 为类视图中的所有方法添加装饰器
def decorator1(func):
def wrapper(*args, **kwargs):
print('decorator1')
return func(*args, **kwargs)
return wrapper
def decorator2(func):
def wrapper(*args, **kwargs):
print('decorator2')
return func(*args, **kwargs)
return wrapper
class DemoResource(Resource):
method_decorators = [decorator1, decorator2]
def get(self):
return {'msg': 'get view'}
def post(self):
return {'msg': 'post view'}
- 为类视图中不同的方法添加不同的装饰器
class DemoResource(Resource):
method_decorators = {
'get': [decorator1, decorator2],
'post': [decorator1]
}
# 使用了decorator1 decorator2两个装饰器
def get(self):
return {'msg': 'get view'}
# 使用了decorator1 装饰器
def post(self):
return {'msg': 'post view'}
# 未使用装饰器
def put(self):
return {'msg': 'put view'}
6.3 关于请求处理
Flask-RESTful 提供了RequestParser
类,用来帮助我们检验和转换请求数据。
from flask_restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('rate', type=int, help='Rate cannot be converted', location='args')
parser.add_argument('name')
args = parser.parse_args()
使用步骤:
-
创建
RequestParser
对象 -
向
RequestParser
对象中添加需要检验或转换的参数声明 -
使用
parse_args()
方法启动检验处理 -
检验之后从检验结果中获取参数时可按照字典操作或对象属性操作
args.rate 或 args['rate']
实列:
from flask import Flask,Blueprint
from flask_restful import Resource,Api
from flask_restful.reqparse import RequestParser
app=Flask(__name__)
api=Api(app)
# demo?a=1&b=2
class DemoResource(Resource):
def get(self):
# 为了校验参数a
# 1.创建RequestParser类对象
rp = RequestParser()
# 2 声明参数 参数的名字跟请求中的参数对应
rp.add_argument('a')
rp.add_argument('b')
# 3 执行校验 返回校验对象
req = rp.parse_args()
# 4 把校验对象当做字典一样 拿参数,也可以当做对象 以属性的方式拿参数
a = req['a'] # 字典
b = req.b # 对象
return {"a":a}
api.add_resource(DemoResource,'/demo')
参数说明
1 required
描述请求是否一定要携带对应参数,默认值为False
-
True 强制要求携带
若未携带,则校验失败,向客户端返回错误信息,状态码400
-
False 不强制要求携带
若不强制携带,在客户端请求未携带参数时,取出值为None
class DemoResource(Resource):
def get(self):
rp = RequestParser()
rp.add_argument('a', required=False)
args = rp.parse_args()
return {'msg': 'data={}'.format(args.a)}
2 help
参数检验错误时返回的错误描述信息
rp.add_argument('a', required=True, help='missing a param')
3 action
描述对于请求参数中出现多个同名参数时的处理方式
action='store'
保留出现的第一个, 默认action='append'
以列表追加保存所有同名参数的值
rp.add_argument('a', required=True, help='missing a param', action='append')
4 type
描述参数应该匹配的类型,(1)可以使用python的标准数据类型string、int,使用标准类型的好处是如果能将参数转化为标准类型,则就转化为标准类型;(2)也可使用Flask-RESTful提供的检验方法,还可以自己定义
-
标准类型
rp.add_argument('a', type=int, required=True, help='missing a param', action='append')
-
Flask-RESTful提供
检验类型方法在
flask_restful.inputs
模块中-
url
-
regex(指定正则表达式)
from flask_restful import inputs rp.add_argument('a', type=inputs.regex(r'^\d{2}&'))
-
natural
自然数0、1、2、3... -
positive
正整数 1、2、3... -
int_range(low ,high)
整数范围rp.add_argument('a', type=inputs.int_range(1, 10))
-
boolean
-
-
自定义
def mobile(mobile_str): """ 检验手机号格式 :param mobile_str: str 被检验字符串 :return: mobile_str """ if re.match(r'^1[3-9]\d{9}$', mobile_str): return mobile_str else: raise ValueError('{} is not a valid mobile'.format(mobile_str)) rp.add_argument('a', type=mobile)
5 location
描述参数应该在请求数据中出现的位置
# Look only in the POST body
parser.add_argument('name', type=int, location='form')
# Look only in the querystring
parser.add_argument('PageSize', type=int, location='args')
# From the request headers
parser.add_argument('User-Agent', location='headers')
# From http cookies
parser.add_argument('session_id', location='cookies')
# From json
parser.add_argument('user_id', location='json')
# From file uploads
parser.add_argument('picture', location='files')
也可指明多个位置
parser.add_argument('text', location=['headers', 'json'])
6.4 关于响应处理
flask_restful中返回的字典类型 可以自动转化为json了,
返回的数据从哪里来?如可以从数据库查询的来,但是查询数据库返回的一般是模型类对象
我们需要借助于模型类转化工具,将模型类转化为字典
1 序列化数据
Flask-RESTful 提供了marshal工具,用来帮助我们将数据序列化为特定格式的字典数据,以便作为视图的返回值。
(1)使用装饰器方式:marshal_with 需要提前预定义转化的字段
from flask_restful import Resource, fields, marshal_with
resource_fields = {
'name': fields.String,
'address': fields.String,
'user_id': fields.Integer
}
class Todo(Resource):
@marshal_with(resource_fields, envelope='resource')
def get(self, **kwargs):
return db_get_todo()
# db_get_todo() 模型类对象 带入到了marshal_with装饰器,转化为 resource_fields 指定的类型。
(2)也可以不使用装饰器,使用函数的方式:marshal
class Todo(Resource):
def get(self, **kwargs):
data = db_get_todo()
return marshal(data, resource_fields)
示例
# 用来模拟要返回的数据对象的类
class User(object):
def __init__(self, user_id, name, age):
self.user_id = user_id
self.name = name
self.age = age
resoure_fields = {
'user_id': fields.Integer,
'name': fields.String
}
class Demo1Resource(Resource):
@marshal_with(resoure_fields, envelope='data1')
def get(self):
user = User(1, 'itcast', 12)
return user
class Demo2Resource(Resource):
def get(self):
user = User(1, 'itcast', 12)
return marshal(user, resoure_fields, envelope='data2')
envelope 把返回的数据放到一个内嵌的字典中{“data1”:{要返回的字典}}
2 定制返回的JSON格式
需求
想要接口返回的JSON数据具有如下统一的格式
{"message": "描述信息", "data": {要返回的具体数据}}
在接口处理正常的情况下, message返回ok即可,但是若想每个接口正确返回时省略message字段
class DemoResource(Resource):
def get(self):
return {'user_id':1, 'name': 'itcast'}
对于诸如此类的接口,能否在某处统一格式化成上述需求格式?
{"message": "OK", "data": {'user_id':1, 'name': 'itcast'}}
解决
Flask-RESTful的Api对象提供了一个representation
的装饰器,允许定制返回数据的呈现格式
api = Api(app)
@api.representation('application/json')
def handle_json(data, code, headers):
# TODO 此处添加自定义处理
return resp
Flask-RESTful原始对于json的格式处理方式如下:
代码出处:flask_restful.representations.json
from flask import make_response, current_app
from flask_restful.utils import PY3
from json import dumps
def output_json(data, code, headers=None):
"""Makes a Flask response with a JSON encoded body"""
settings = current_app.config.get('RESTFUL_JSON', {})
# If we're in debug mode, and the indent is not set, we set it to a
# reasonable value here. Note that this won't override any existing value
# that was set. We also set the "sort_keys" value.
if current_app.debug:
settings.setdefault('indent', 4)
settings.setdefault('sort_keys', not PY3)
# always end the json dumps with a new line
# see https://github.com/mitsuhiko/flask/pull/1262
dumped = dumps(data, **settings) + "\n"
resp = make_response(dumped, code)
resp.headers.extend(headers or {})
return resp
为满足需求,做如下改动即可
@api.representation('application/json')
def output_json(data, code, headers=None):
"""Makes a Flask response with a JSON encoded body"""
# 此处为自己添加***************
if 'message' not in data:
data = {
'message': 'OK',
'data': data
}
# **************************
settings = current_app.config.get('RESTFUL_JSON', {})
# If we're in debug mode, and the indent is not set, we set it to a
# reasonable value here. Note that this won't override any existing value
# that was set. We also set the "sort_keys" value.
if current_app.debug:
settings.setdefault('indent', 4)
settings.setdefault('sort_keys', not PY3)
# always end the json dumps with a new line
# see https://github.com/mitsuhiko/flask/pull/1262
dumped = dumps(data, **settings) + "\n"
resp = make_response(dumped, code)
resp.headers.extend(headers or {})
return resp
将返回的对象封装成json格式