Flask 学习-75.Flask-RESTX 使用 marshal_with 处理嵌套字段

前言

使用 marshal_with 序列化模型非常方便,还可以处理一些嵌套字段。

嵌套字段

虽然使用 dicts 嵌套字段可以将平面数据对象转换为嵌套响应,但您可以使用它 Nested 来解组嵌套数据结构并适当地呈现它们。

官方文档示例

>>> from flask_restx import fields, marshal
>>> import json
>>>
>>> address_fields = {}
>>> address_fields['line 1'] = fields.String(attribute='addr1')
>>> address_fields['line 2'] = fields.String(attribute='addr2')
>>> address_fields['city'] = fields.String(attribute='city')
>>> address_fields['state'] = fields.String(attribute='state')
>>> address_fields['zip'] = fields.String(attribute='zip')
>>>
>>> resource_fields = {}
>>> resource_fields['name'] = fields.String
>>> resource_fields['billing_address'] = fields.Nested(address_fields)
>>> resource_fields['shipping_address'] = fields.Nested(address_fields)
>>> address1 = {'addr1': '123 fake street', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> address2 = {'addr1': '555 nowhere', 'city': 'New York', 'state': 'NY', 'zip': '10468'}
>>> data = {'name': 'bob', 'billing_address': address1, 'shipping_address': address2}
>>>
>>> json.dumps(marshal(data, resource_fields))
'{"billing_address": {"line 1": "123 fake street", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}, 
"name": "bob", "shipping_address": {"line 1": "555 nowhere", "line 2": null, "state": "NY", "zip": "10468", "city": "New York"}}'

此示例使用两个Nested字段。构造Nested函数需要一个字段字典来呈现为 sub-fields.input。构造函数和嵌套字典(上一个示例)之间的重要区别在于Nested属性的上下文。
在此示例中, billing_address是一个具有自己的字段的复杂对象,并且传递给嵌套字段的上下文是子对象而不是原始data对象。
换句话说: data.billing_address.addr1在这里是在范围内,而在前面的例子data.addr1中是位置属性。记住:对象Nested为List属性创建了一个新的范围。

默认情况下,当子对象为None时,将生成具有嵌套字段默认值的对象,而不是null。这可以通过传递allow_null参数来修改,Nested有关更多详细信息,请参阅构造函数。
使用NestedwithList来编组更复杂对象的列表:

user_fields = api.model('User', {
    'id': fields.Integer,
    'name': fields.String,
})

user_list_fields = api.model('UserList', {
    'users': fields.List(fields.Nested(user_fields)),
})

使用示例

比如我们想返回以下格式, data 是查询的对象序列化后的json

{
    "code": 0,
    "msg": "success",
    "data": {
        "id": 1
        ......
    }
}

使用 fields.Nested 嵌套字段

teacher_model = api.model('TeacherModel', {
    'name': fields.String(
        max_length=50, required=True, description='姓名'),
    'size': fields.String(
        enum=["SMALL", "MEDIUM", "LARGE"], required=False, description='型号'),
    'address': fields.String(max_length=150, description='邮箱')
})


new_fields = {}
new_fields['code'] = fields.Integer(default=0)
new_fields['message'] = fields.String(default='success')
new_fields['data'] = fields.Nested(teacher_model)

在返回的时候,就不能直接返回模型了,需按new_fields结构返回

@api.route('/teacher')
class TeacherView(Resource):

    @api.doc(description='新增老师')
    @api.marshal_with(new_fields)
    @api.expect(teacher_model, validate=True)
    def post(self):
        """
            add teacher
        """
        api.logger.info(f"获取请求参数: {api.payload}")
        t = Teachers(
                name=api.payload.get('name'),
                size=api.payload.get('size'),
                address=api.payload.get('address'),
            )
        t.save()  # 保存数据
        return {"data": t}, HTTPStatus.CREATED

测试接口

POST http://127.0.0.1:5000/api/v1/teacher HTTP/1.1
User-Agent: Fiddler
Host: 127.0.0.1:5000
Content-Length: 18
Content-Type: application/json

{"name": "yoyo"}

HTTP/1.0 201 CREATED
Content-Type: application/json
Content-Length: 141
Server: Werkzeug/2.0.2 Python/3.8.5
Date: Fri, 23 Sep 2022 02:03:31 GMT

{
    "code": 0,
    "message": "success",
    "data": {
        "name": "yoyo",
        "size": "MEDIUM",
        "address": null
    }
}
posted @ 2022-09-23 10:06  上海-悠悠  阅读(275)  评论(0编辑  收藏  举报