【问题标题】:JSON serialization using Marshmallow - skip None attributes使用 Marshmallow 的 JSON 序列化 - 跳过无属性
【发布时间】:2019-03-11 19:04:28
【问题描述】:

我正在使用 Marshmallow 将我的决策类的实例发送到 JSON。但是,这也会转储 None 的属性,例如我的属性 score 将转换为 JSON 格式的 null。之后,我无法使用相同的方法再次读取 JSON。

https://repl.it/repls/VoluminousMulticoloredFacts

最后一行是它当前失败的地方。我需要在加载过程中不将None 转储到 JSON 或跳过 null

import json
from marshmallow import Schema, fields, post_load

json_data = """{
    "appid": "2309wfjwef",
    "strategy": "First Strategy"
}"""

# Output class definition
class Decision(object):
    def __init__(self, appid = None, strategy = None, score = None):
        self.appid = appid
        self.strategy = strategy
        self.score = score

class DecisionSchema(Schema):
    appid = fields.Str()
    strategy = fields.Str()
    score = fields.Int()

    @post_load
    def make_decision(self, data):
        return Decision(**data)

# Deserialization into object
dec_json = json.loads(json_data)
schema = DecisionSchema()
dec = schema.load(dec_json).data

print(dec.strategy)

# Dump results back to JSON
schema = DecisionSchema()
out = schema.dumps(dec)

print(out.data)

# Load back from dump
schema = DecisionSchema()
dec = schema.load(out).data

#print(dec.strategy) # returns error currently

【问题讨论】:

    标签: json python-3.x serialization marshmallow


    【解决方案1】:

    棉花糖开发团队的“官方”回答可以在 bugtracker 的this comment 中找到:

    使用post_dump 方法。

    from marshmallow import Schema, fields, post_dump
    
    class BaseSchema(Schema):
        SKIP_VALUES = set([None])
    
        @post_dump
        def remove_skip_values(self, data, **kwargs):
            return {
                key: value for key, value in data.items()
                if value not in self.SKIP_VALUES
            }
    
    
    class MySchema(BaseSchema):
        foo = fields.Field()
        bar = fields.Field()
    
    
    sch = MySchema()
    sch.dump({'foo': 42, 'bar': None}).data  # {'foo': 42}
    

    正如我在a further comment 中指出的那样,有一个缺点:当字段的allow_noneTrue 时,它也会删除None

    【讨论】:

    • 另一个问题是,如果你使用ordered = True,它会弄乱你的字段顺序
    • 当然。可以修改该方法以保持顺序并返回OrderedDict
    • 不错。由于版本post_load 总是传递参数many,所以方法应该看起来像def remove_skip_values(self, data, many):
    • 是的,从 marshmallow 3 开始,装饰方法必须接受 **kwargs。
    【解决方案2】:

    正如我在上面的评论中指出的那样,如果您使用

    class Meta:
        fields = (
            'field1', 'field2'
        )
        ordered = True
    

    为了解决这个问题,我使用了这个:

    # Remove None fields
    @pre_dump
    def remove_skip_values(self, data):
        return {
            key: value for key, value in data.items()
            if value is not None
        }
    

    这适用于我的对象字典

    【讨论】:

    • 这是更可靠的选择!应该是我接受的!
    • 我们能否通过初始参数remove_none 使其成为可选参数,例如 MySchema(remove_none=True).dump(obj) ?
    • 我收到一个错误:remove_skip_values() got an unexpected keyword argument 'many'
    猜你喜欢
    • 2013-04-11
    • 1970-01-01
    • 1970-01-01
    • 2018-12-14
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多