【flask】请求参数解析校验、响应序列化、自定义响应json

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)
Flask 中,可以使用 Flask-RESTful 或 Flask-Inputs 等第三方库来实现接口参数校验Flask-RESTful: Flask-RESTful 提供了 RequestParser 类来进行参数解析校验,示例代码如下: ```python from flask_restful import reqparse, abort, Api, Resource # 初始化 RequestParser 对象 parser = reqparse.RequestParser() # 添加参数校验规则 parser.add_argument('name', type=str, required=True, help='Name cannot be blank') parser.add_argument('age', type=int, required=True, help='Age cannot be blank') class User(Resource): def post(self): # 解析参数 args = parser.parse_args() # 校验参数 if args['name'] == 'Tom': abort(400, message='Name already exists') # 处理业务逻辑 user = {'name': args['name'], 'age': args['age']} return user, 201 # 注册路由 api = Api(app) api.add_resource(User, '/user') ``` 上述代码中,我们创建了一个名为 User 的资源类,其中 post 方法用于处理 POST 请求。在 post 方法中,我们首先使用 RequestParser 对象解析参数,然后校验参数是否符合要求,最后处理业务逻辑并返回结果。 Flask-Inputs: Flask-Inputs 提供了多种参数校验器,包括字符串长度、数字范围、正则表达式等,示例代码如下: ```python from flask import Flask, jsonify from flask_inputs import Inputs from flask_inputs.validators import JsonSchema # 初始化 Inputs 对象 inputs = Inputs() # 添加参数校验规则 schema = { 'type': 'object', 'properties': { 'name': {'type': 'string', 'minLength': 1}, 'age': {'type': 'integer', 'minimum': 0, 'maximum': 200} }, 'required': ['name', 'age'] } inputs.add('json', JsonSchema(schema=schema)) @app.route('/user', methods=['POST']) def create_user(): # 校验参数 if inputs.validate(): # 处理业务逻辑 user = {'name': inputs.json['name'], 'age': inputs.json['age']} return jsonify(user), 201 else: return jsonify(errors=inputs.errors), 400 ``` 上述代码中,我们创建了一个名为 create_user 的路由,其中使用 Inputs 对象添加了参数校验规则,然后在路由处理函数中校验参数并处理业务逻辑。如果参数校验失败,我们将返回 400 错误和错误信息。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰冷的希望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值