我正在尝试在一个扩展棉花糖的类中实现一些逻辑。架构,以便我可以覆盖用pre_dump修饰的方法中其中一个字段的 load_only 属性的默认值。
默认情况下,load_only=True,但我希望能够在某些情况下将其设置为 False,并认为实现这一目标的最佳方法是设置一个可以在预转储方法中检查的上下文值,然后设置 load_only=False 以在序列化期间包含该字段。
为了演示这一点,我有一个 ParentSchema 类和一个 ChildSchema 类。 ParentSchema 有一个名为 children 的字段,其中包含 ChildSchema 对象列表。
from marshmallow import Schema, fields, post_load, pre_dump
import json
class Child(object):
def __init__(self, id=None, data=None, parent_id=None):
self.id = id
self.data = data
self.parent_id = parent_id
def __repr__(self):
return 'id=' + str(self.id) + ', data=' + str(self.data) + ', parent_id=' + str(self.parent_id)
class ChildSchema(Schema):
id = fields.Integer(dump_only=True)
data = fields.String(required=True)
parent_id = fields.Integer(required=False)
@post_load
def make_child(self, data, **kwargs):
return Child(**data)
class Parent(object):
def __init__(self, id=None, data=None, children=None):
self.id = id
self.data = data
self.children = children
def __repr__(self):
return 'id=' + str(self.id) + ', data=' + str(self.data) + ', children=' + str(self.children)
class ParentSchema(Schema):
id = fields.Integer(dump_only=True)
data = fields.String(required=True)
children = fields.Nested(ChildSchema, many=True, load_only=True)
@post_load
def make_parent(self, data, **kwargs):
return Parent(**data)
@pre_dump
def check_context(self, data, **kwargs):
if 'dump_children' in self.context:
self.fields['children'].load_only = False
return data
默认行为应该是不序列化子字段,但如果在创建 ParentSchema 对象时在上下文字典中提供了键"dump_children",则load_only设置为 False,我希望这会导致子字段被序列化。
parent_data = [
{
"data": "parent 1",
"children": [
{
"data": "child 1"
},
{
"data": "child 2"
}
]
},
{
"data": "parent 2",
"children": [
{
"data": "child 3"
}
]
}
]
parents = ParentSchema(context={'dump_children': True}, many=True).dump(parent_data)
print(json.dumps(parents, indent=2))
我不明白的是,为什么尽管load_only按预期设置为 False,但这会产生:
[
{
"data": "parent 1"
},
{
"data": "parent 2"
}
]
而不是:
[
{
"data": "parent 1",
"children": [
{
"data": "child 1"
},
{
"data": "child 2"
}
]
},
{
"data": "parent 2",
"children": [
{
"data": "child 3"
}
]
}
]
是否有其他逻辑阻止此字段被序列化?还是有更好的方法来实现我所追求的?
所以我想用context
做类似的事情来控制被倾倒的内容,我遇到了你的问题。在source code
中稍加挖掘表明,转储过程不会动态确定使用带有load_only=False
的字段要输出的字段。事实上,在架构实例初始化后更改字段上的该属性似乎根本没有效果。相反,它使用dump_fields
属性确定要转储哪些字段,该属性在通过_init_fields()
方法初始化时设置。从理论上讲,您可以在更改children
的load_only
属性后再次调用该方法,但它是一个私有的 api 方法,这似乎很黑客。
如果您想有条件地控制输出的内容,我认为最好使用only
/exclude
:
parents_only = ParentSchema(exclude=('children',), many=True)
parents_only.dump(parent_data)
[{'data': 'parent 1'}, {'data': 'parent 2'}]
parents_and_children = ParentSchema(many=True)
parents_and_children.dump(parent_data)
[{'data': 'parent 1', 'children': [{'data': 'child 1'}, {'data': 'child 2'}]}, {'data': 'parent 2', 'children': [{'data': 'child 3'}]}]
就我个人而言,我觉得有点奇怪,only
/exclude
是类级别的参数,而不是dump
上的参数,但是在这个GitHub问题和这个问题中有一些讨论。
除了创建像这样的单独模式实例(您已经在这样做并在上下文中传递(之外,您可能会将某些内容一起破解以动态修改dump_fields
但这似乎不太可取,并且可能会给您带来更多问题。