当前位置: 首页 > 工具软件 > flask-restx > 使用案例 >

Flask 学习-48.Flask-RESTX 使用api.model() 模型工厂

芮博厚
2023-12-01

前言

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"}
 类似资料: