• Flask 学习48.FlaskRESTX 使用api.model() 模型工厂 上海


    前言

    model()工厂允许您将模型实例化并注册到您的API或Namespace.

    api.model() 工厂

    有2种使用方式,第一种直接使用 api.model

    my_fields = api.model('MyModel', {
        'name': fields.String,
        'age': fields.Integer(min=0)
    })
    
    

    第二种间接注册到api,以下方式是等价的

    # Equivalent to
    my_fields = Model('MyModel', {
        'name': fields.String,
        'age': fields.Integer(min=0)
    })
    api.models[my_fields.name] = my_fields
    

    使用示例

    user模型

    class Users(db.Model):
        __tablename__ = 'user'  # 数据库表名
        id = db.Column(db.Integer, primary_key=True, autoincrement=True)
        username = db.Column(db.String(50), unique=True, nullable=False)
        password = db.Column(db.String(128), nullable=False)
        is_active = db.Column(db.Boolean, default=1)
        email = db.Column(db.String(64), nullable=True)
        create_time = db.Column(db.DateTime, default=datetime.now)
        update_time = db.Column(db.DateTime, onupdate=datetime.now, default=datetime.now)
    
        def hash_password(self, password):
            """密码加密"""
            self.password = sha256_crypt.encrypt(password)
    
        def verify_password(self, password):
            """校验密码"""
            return sha256_crypt.verify(password, self.password)
    
        def __repr__(self):
            return f"<Users(id='{self.id}', username='{self.username}'...)>"
    

    校验请求入参,除了之前学到的 RequestParser 来定义预期的输入:

    @api.route('/api/user', endpoint='user')
    class UserView(Resource):
    
        def post(self):
            """add user"""
            parser = reqparse.RequestParser()
            parser.add_argument('username', required=True, type=str, help='username is required')
            parser.add_argument('password', required=True, type=str, help='password is required')
            args = parser.parse_args()
            print(f'请求参数: {args}')
            # 保存数据库
            return {"msg": "create success"}
    

    也可以使用api.model() 的方法来校验请求入参, 以下方式是等价的

    from flask_restx import Resource, fields
    
    user_input = api.model('UserModel', {
        'username': fields.String(required=True),
        'password': fields.String(required=True)
    })
    
    
    @api.route('/api/user', endpoint='user')
    class UserView(Resource):
    
        @api.expect(user_input, validate=True)
        def post(self):
            """add user"""
            print(f'请求参数: {api.payload}')
            # 保存数据库
            return {"msg": "create success"}
    

    @api.expect 装饰器

    装饰器@api.expect() 允许您指定预期的输入字段。它接受一个可选的布尔参数 validate,指示是否应验证有效payload 参数。
    RESTX_VALIDATE可以通过将配置设置为True 或传递validate=True给 API 构造函数来全局自定义验证行为。

    以下示例是等效的, 未设置validate=True 功能等价于@api.expect() 功能跟 api.doc() 一样(api.doc() 用于 swagger 文档输出)

    使用@api.expect()装饰器:

    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>')
    class MyResource(Resource):
        @api.expect(resource_fields)
        def get(self):
            pass
    

    使用api.doc()装饰器:

    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>')
    class MyResource(Resource):
        @api.doc(body=resource_fields)
        def get(self):
            pass
    

    您可以将列表指定为预期输入:

    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>')
    class MyResource(Resource):
        @api.expect([resource_fields])
        def get(self):
            pass
    

    您可以使用RequestParser来定义预期的输入:

    parser = api.parser()
    parser.add_argument('param', type=int, help='Some param', location='form')
    parser.add_argument('in_files', type=FileStorage, location='files')
    
    
    @api.route('/with-parser/', endpoint='with-parser')
    class WithParserResource(restx.Resource):
        @api.expect(parser)
        def get(self):
            return {}
    

    启用或禁用 validate 验证:

    可以在特定端点上启用或禁用验证:

    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>')
    class MyResource(Resource):
        # Payload validation disabled  禁用validate 校验入参
        @api.expect(resource_fields)
        def post(self):
            pass
    
        # Payload validation enabled  启用validate 校验入参
        @api.expect(resource_fields, validate=True)
        def post(self):
            pass
    

    通过配置进行应用程序范围验证的示例:

    app.config['RESTX_VALIDATE'] = True
    
    api = Api(app)
    
    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>')
    class MyResource(Resource):
        # Payload validation enabled
        @api.expect(resource_fields)
        def post(self):
            pass
    
        # Payload validation disabled
        @api.expect(resource_fields, validate=False)
        def post(self):
            pass
    

    通过构造函数进行应用程序范围验证的示例:

    api = Api(app, validate=True)
    
    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>')
    class MyResource(Resource):
        # Payload validation enabled
        @api.expect(resource_fields)
        def post(self):
            pass
    
        # Payload validation disabled
        @api.expect(resource_fields, validate=False)
        def post(self):
            pass
    

    @api.marshal_with()装饰器

    这个装饰器像原始marshal_with()装饰器一样工作,不同之处在于它记录了方法。可选参数code允许您指定预期的 HTTP 状态代码(默认为 200)。可选参数as_list允许您指定对象是否作为列表返回。

    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>', endpoint='my-resource')
    class MyResource(Resource):
        @api.marshal_with(resource_fields, as_list=True)
        def get(self):
            return get_objects()
    
        @api.marshal_with(resource_fields, code=201)
        def post(self):
            return create_object(), 201
    

    Api.marshal_list_with() 装饰器严格等价于 Api.marshal_with(fields, as_list=True)()

    resource_fields = api.model('Resource', {
        'name': fields.String,
    })
    
    @api.route('/my-resource/<id>', endpoint='my-resource')
    class MyResource(Resource):
        @api.marshal_list_with(resource_fields)
        def get(self):
            return get_objects()
    
        @api.marshal_with(resource_fields)
        def post(self):
            return create_object()
    

    使用示例

    post 请求校验请求入参,get 请求查询数据序列化输出内容

    
    from flask_restx import Resource, fields
    
    user_input = api.model('UserModel', {
        'username': fields.String(required=True),
        'password': fields.String(required=True)
    })
    
    out_fields = api.model('UserInfo', {
        'username': fields.String,
        'email': fields.String,
        'create_time': fields.DateTime(dt_format='rfc822')
    })
    
    
    @api.route('/api/user', endpoint='user')
    class UserView(Resource):
    
        @api.marshal_with(out_fields, envelope='users')
        def get(self):
            """查询全部"""
            users = models.Users.query.all()
            return users
    
        @api.expect(user_input, validate=True)
        def post(self):
            """add user"""
            print(f'请求参数: {api.payload}')
            # 保存数据库
            return {"msg": "create success"}
    
    

    get请求查询结果

    GET http://127.0.0.1:5000/api/user HTTP/1.1
    
    
    {
        "users": [
            {
                "username": "test",
                "email": null,
                "create_time": "Mon, 05 Sep 2022 11:13:16 -0000"
            },
            {
                "username": "test1",
                "email": null,
                "create_time": "Mon, 05 Sep 2022 13:10:41 -0000"
            },
            {
                "username": "test12",
                "email": null,
                "create_time": "Mon, 05 Sep 2022 13:10:55 -0000"
            }
        ]
    }
    

    user_input 和 out_fields 模型可以合并为一个,有些不需要校验,但是可以输出的用readonly=True表示

    from flask_restx import Resource, fields
    
    user_model = api.model('UserModel', {
        'id': fields.Integer(readonly=True),
        'username': fields.String(required=True),
        'password': fields.String(required=True),
        'is_active': fields.Boolean(),
        'email': fields.String(),
        'create_time': fields.DateTime(dt_format='rfc822'),
        'update_time': fields.DateTime(dt_format='rfc822')
    })
    
    
    @api.route('/api/user', endpoint='user')
    class UserView(Resource):
    
        @api.marshal_with(user_model, envelope='users')
        def get(self):
            """查询全部"""
            users = models.Users.query.all()
            return users
    
        @api.expect(user_model, validate=True)
        def post(self):
            """add user"""
            print(f'请求参数: {api.payload}')
            # 保存数据库
            return {"msg": "create success"}
    
  • 相关阅读:
    JS小白进阶之路(2)
    JS小白进阶之路(1)
    ajax.readyState与ajax.status一览
    Photoshop投影和CSS box-shadow转换
    layer弹层插件
    [Intervention] Ignored attempt to cancel a touchmove event with cancelable=false, for example because scrolling is in progress and cannot be interrupted
    css清除浮动影响
    css网页重置样式表(多版本)
    XSS攻击和CSRF攻击的定义及区别
    git的cd命令
  • 原文地址:https://www.cnblogs.com/yoyoketang/p/16657864.html
Copyright © 2020-2023  润新知