前言
使用 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
}
}