有条件地更改Python Marshmallow中的字段属性

有条件地更改Python Marshmallow中的字段属性,python,marshmallow,Python,Marshmallow,我试图在一个扩展了marshmallow.Schema的类中实现一些逻辑,这样我就可以覆盖一个用pre_dump修饰的方法中某个字段的load_only属性的默认值 默认情况下,load_only=True,但我希望在某些情况下能够将其设置为False,并认为实现这一点的最佳方法是设置一个可以在pre-dump方法中检查的上下文值,然后将load_only=False设置为在序列化过程中包括该字段 为了演示这一点,我有一个ParentSchema类和一个ChildSchema类。ParentSc

我试图在一个扩展了marshmallow.Schema的类中实现一些逻辑,这样我就可以覆盖一个用pre_dump修饰的方法中某个字段的load_only属性的默认值

默认情况下,load_only=True,但我希望在某些情况下能够将其设置为False,并认为实现这一点的最佳方法是设置一个可以在pre-dump方法中检查的上下文值,然后将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
默认行为应该是不序列化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字段
,但这样做似乎不太明智,而且可能会给您自己带来更多问题。

谢谢您的建议-这似乎是一个不错的方法。最后,我使用不同的类来定义不同的模式。