我是靠谱客的博主 傻傻黄豆,这篇文章主要介绍Flask 视图 请求 序列化,现在分享给大家,希望可以做个参考。

Flask-RESTful 是一个 Flask 扩展,它添加了快速构建 REST APIs 的支持。

环境安装

复制代码
1
2
pip install flask-restful

构建RESTAPI

使用 flask-restful 构建RESTAPI只需要进行三步操作

  • 创建扩展/组件对象
复制代码
1
2
组件对象 = Api(app)
  • 定义类视图
复制代码
1
2
class 自定义视图类(Resource):
  • 组件添加类视图
复制代码
1
2
组件对象.add_resource(视图类, URL资源段)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from flask import Flask from flask_restful import Api, Resource app = Flask(__name__) # 1. 创建API对象 用于管理类视图(资源) api = Api(app) # 2.定义类视图 继承Resource class DemoResource(Resource): def get(self): # 类视图响应的content-type默认变为json形式 # 类视图的返回值可以是字典, 会被自动转为json字符串 return {'foo': 'get'} def post(self): return {'foo': 'post'} # 3.添加类视图 函数标记默认为类名小写 api.add_resource(DemoResource, '/', endpoint='demo') # @app.route('/') # def index(): # # return "index" if __name__ == '__main__': print(app.url_map) app.run(debug=True)
  • 类视图的优点
    视图响应的 content-type 默认变为 JSON形式
    类视图的 返回值可以是字典, 会被自动转为json字符串
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
from flask import Flask from flask_restful import Resource, Api app = Flask(__name__) api = Api(app) def deco1(f): def wrapper(*args, **kwargs): print('deco1') return f(*args, **kwargs) return wrapper def deco2(f): def wrapper(*args, **kwargs): print('deco2') return f(*args, **kwargs) return wrapper class DemoResource(Resource): # 通过method_decorators类属性来设置类视图的装饰器 # method_decorators = [deco1, deco2] # 列表形式 所有请求方式都会使用 method_decorators = {'get': [deco1], 'post': [deco2]} # 字典形式 给请求方式分别设置装饰器 # @deco2 # @deco1 def get(self): return {'foo': "get"} def post(self): return {'foo': "post"} api.add_resource(DemoResource, '/') if __name__ == '__main__': app.run(debug=True)

蓝图和类视图

蓝图和类视图可以配合使用, 步骤如下:
创建蓝图对象

复制代码
1
2
蓝图对象 = Blueprint('蓝图名', __name__)

每个蓝图分别创建组件对象

复制代码
1
2
组件对象 = Api(蓝图对象)

组件对象添加类视图

复制代码
1
2
组件对象.add_resource(视图类, URL资源段)

应用注册蓝图

复制代码
1
2
应用对象.register_blueprint(蓝图对象)

在 user包中创建 views文件, 定义类视图

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
# user/views.py from flask_restful import Resource class DemoResource(Resource): def get(self): return {'get': 'hello'} def post(self): return {'post': 'world'}

在 user包 的初始化文件 init.py 中

  • 创建蓝图对象
  • 通过蓝图对象创建对应的组件对象
  • 组件对象添加类视图
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# user/__init__.py from flask import Blueprint from flask_restful import Api from user.views import DemoResource # 1.创建蓝图对象 user_blu = Blueprint('user', __name__, url_prefix='/user') # 2.创建蓝图对应的api对象 user_api = Api(user_blu) # 3.添加类视图 user_api.add_resource(DemoResource, '/')

想要让蓝图对象能够完成路由定义, 还需要 Flask应用注册蓝图对象

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# main.py from flask import Flask from user import user_blu app = Flask(__name__) # 4.注册蓝图 app.register_blueprint(user_blu) if __name__ == '__main__': print(app.url_map) app.run(debug=True, port=8000)

在这里插入图片描述

请求

1. 请求解析
通过前一阶段的学习, 我们知道 DRF框架 的核心功能 序列化器, 包括以下功能
反序列化

  • 参数解析 RequestParser
  • 数据保存

序列化
marshal函数

flask-restful 没有提供数据保存功能, 数据存储可以使用后续的flask-sqlalchemy扩展 来完成

RequestParser 负责请求解析工作, 基本步骤如下
创建请求解析器

复制代码
1
2
请求解析器 = RequestParser()

添加参数规则

复制代码
1
2
请求解析器.add_argument(参数名, 参数规则..)

执行解析

复制代码
1
2
参数对象 = 请求解析器.parse_args()

获取参数

复制代码
1
2
参数对象.参数名
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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): # 1.创建请求解析器 parser = RequestParser() # 2.添加参数规则 parser.add_argument('name') parser.add_argument('age') # 3.执行解析 默认会从 查询字符串/post键值对/post-json数据 进行参数提取 args = parser.parse_args() # 4.获取参数 print(args.name) print(args.age) return {'foo': "get"} api.add_resource(DemoResource, '/') if __name__ == '__main__': app.run(debug=True)

2.常用参数
在这里插入图片描述
default & required & location参数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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 post(self): parser = RequestParser() parser.add_argument('name', required=True, location='json') parser.add_argument('age', default=10) args = parser.parse_args() print(args.name) print(args.age) return {'foo': "post"} api.add_resource(DemoResource, '/') if __name__ == '__main__': app.run(debug=True)

type参数
类型转换和格式校验

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from flask import Flask from flask_restful import Resource, Api from flask_restful.reqparse import RequestParser 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 put(self): parser = RequestParser() parser.add_argument('name') # parser.add_argument('age', type=int) # 转为int类型 # parser.add_argument('age', type=boolean) # 转为bool类型 1/0 true/false # parser.add_argument('age', type=date) # 日期 转为datetime类型 YYYY-mm-dd # parser.add_argument('age', type=datetime_from_iso8601) # 时间 转为datetime类型 2012-01-01T23:30:00+02:00 # parser.add_argument('age', type=int_range(5, 10)) # 转为int类型 限定范围[5, 10] # parser.add_argument('age', type=regex(r'^1[3-9]d{9}$')) # 要求匹配正则 parser.add_argument('age', type=func1) # 自定义函数 args = parser.parse_args() print(args.name) print(args.age) print(type(args.age)) return {'foo': 'put'} api.add_resource(DemoResource, '/') if __name__ == '__main__': app.run(debug=True)

序列化

flask-restful 通过 marshal函数 来完成序列化处理
定义序列化规则

复制代码
1
2
序列化规则 = {字段名: 序列化类型}

marshal函数 按照序列化规则 将模型对象转为字典

复制代码
1
2
序列化后的字典 = marshal(模型对象, 序列化规则)
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
from flask import Flask from flask_restful import Resource, Api, marshal_with, fields app = Flask(__name__) api = Api(app) class User: # 定义模型类 def __init__(self): self.name = 'zs' self.age = 20 self.height = 1.8 self.scores = [80, 90] self.info = { 'gender': True } fields = { # 序列化规则 'username': fields.String(attribute='name'), # 指定对应的模型属性 'age': fields.Integer(default=10), # 设置默认值 'height': fields.Float, 'scores': fields.List(fields.Integer), # 元素类型唯一 'info': fields.Nested({'gender': fields.Boolean}) } class DemoResource(Resource): method_decorators = {'post': [marshal_with(fields)]} def post(self): user1 = User() # 如果设置了marshal_with装饰器, 可以直接返回模型对象 return user1 api.add_resource(DemoResource, '/') if __name__ == '__main__': app.run(debug=True)

在这里插入图片描述
在这里插入图片描述
marshal_with 装饰器
在这里插入图片描述

实际开发中, 考虑到序列化的复杂性, 部分公司还会采用 自定义方法 的方式来完成序列化处理

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
from flask import Flask from flask_restful import Resource, Api app = Flask(__name__) api = Api(app) class User: def __init__(self): self.name = 'zs' self.age = 20 self.height = 1.8 self.scores = [80, 90] self.info = { 'gender': True } def to_dict(self): # 自定义模型转换方法 return { 'name': self.name, 'age': self.age } class DemoResource(Resource): def put(self): user1 = User() return user1.to_dict() api.add_resource(DemoResource, '/') if __name__ == '__main__': app.run(debug=True)

自定义JSON

实际开发中, 返回的JSON数据中除了包含基础数据, 往往还需要设置一些 统一的外层包装, 以便前端进行更好的解析处理, 如:

复制代码
1
2
3
4
5
6
7
8
9
{ "message": "ok", // 外层包装 "code": 200, // 外层包装 "data": { // 基础数据 "name": "张三", "age": 20 } }
  • flask-restful 提供了 api.representation()装饰器方法, 允许开发者自定义返回的数据格式
  • 在实现自定义JSON格式时, 可以参考 flask-restful 默认转换函数 (字典转json数据) 的源代码
  • 默认转换函数的源代码:
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# flask_restful/representations/json.py 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
复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
from collections import OrderedDict 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) @api.representation('application/json') # 指定响应形式对应的转换函数 def output_json(data, code, headers=None): """自定义json形式""" # 根据flask内置配置, 进行格式处理(缩进/key是否排序等) 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 } # 字典转json字符串 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)

在这里插入图片描述

实际开发中, 可能还会展开装饰器来设置自定义响应格式

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def output_json(data, code, headers=None): """自定义json形式""" # 根据flask内置配置, 进行格式处理(缩进/key是否排序等) 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 } # 字典转json字符串 dumped = dumps(data, **settings) + "n" # 构建响应对象 resp = make_response(dumped, code) resp.headers.extend(headers or {}) return resp # 展开装饰器的形式设置自定义响应形式 api.representation('application/json')(output_json)

最后

以上就是傻傻黄豆最近收集整理的关于Flask 视图 请求 序列化的全部内容,更多相关Flask内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(74)

评论列表共有 0 条评论

立即
投稿
返回
顶部