有条件地更改Python Marshmallow中的字段属性
我试图在一个扩展了marshmallow.Schema的类中实现一些逻辑,这样我就可以覆盖一个用pre_dump修饰的方法中某个字段的load_only属性的默认值 默认情况下,load_only=True,但我希望在某些情况下能够将其设置为False,并认为实现这一点的最佳方法是设置一个可以在pre-dump方法中检查的上下文值,然后将load_only=False设置为在序列化过程中包括该字段 为了演示这一点,我有一个ParentSchema类和一个ChildSchema类。ParentSchema有一个名为children的字段,其中包含ChildSchema对象的列表有条件地更改Python Marshmallow中的字段属性,python,marshmallow,Python,Marshmallow,我试图在一个扩展了marshmallow.Schema的类中实现一些逻辑,这样我就可以覆盖一个用pre_dump修饰的方法中某个字段的load_only属性的默认值 默认情况下,load_only=True,但我希望在某些情况下能够将其设置为False,并认为实现这一点的最佳方法是设置一个可以在pre-dump方法中检查的上下文值,然后将load_only=False设置为在序列化过程中包括该字段 为了演示这一点,我有一个ParentSchema类和一个ChildSchema类。ParentSc
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
默认行为应该是不序列化children字段,但如果在创建ParentSchema对象时上下文dict中提供了键“dump\u children”,则load\u only设置为False,我希望这会导致序列化children字段
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_仅按预期设置为False,但为什么会产生:
[
{
"data": "parent 1"
},
{
"data": "parent 2"
}
]
而不是:
[
{
"data": "parent 1",
"children": [
{
"data": "child 1"
},
{
"data": "child 2"
}
]
},
{
"data": "parent 2",
"children": [
{
"data": "child 3"
}
]
}
]
是否有其他逻辑阻止此字段被序列化?还是有更好的方法来实现我的目标?所以我想做一些类似的事情,使用
上下文来控制哪些内容被丢弃,我遇到了你的问题。在中稍微挖掘一下,就会发现转储过程不会使用load\u only=False的字段动态确定要输出的字段。事实上,在初始化模式实例之后更改字段上的属性似乎根本没有效果。相反,它使用\u init\u fields()
方法初始化时设置的dump\u fields
属性来确定要转储哪些字段。理论上,在更改children
的load\u only
属性后,您可能可以再次调用该方法,但它是一个私有api方法,看起来非常粗糙
如果您想有条件地控制输出内容,我认为最好只使用
/排除:
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'}]}]
我个人觉得有点奇怪,只有
/排除
是类级别的参数,而不是转储
上的参数,但在和中也有一些关于这一点的讨论
除了像这样创建单独的模式实例(您已经在这样做并在上下文中传递)之外您可能会一起修改一些内容来动态修改dump\u字段
,但这样做似乎不太明智,而且可能会给您自己带来更多问题。谢谢您的建议-这似乎是一个不错的方法。最后,我使用不同的类来定义不同的模式。