代码之家  ›  专栏  ›  技术社区  ›  camaya

反序列化棉花糖中的嵌套字段

  •  12
  • camaya  · 技术社区  · 8 年前

    我正在使用一个返回如下内容的API:

    {'name': 'foo', 'start': {'date': '2016-06-19', 'time': '18:00'}}
    

    我想用棉花糖来消除它的种族歧视,只得到名字和开始日期,所以理想的结果如下:

    {'name': 'foo', 'date': '2016-06-19'}
    

    但我没有找到任何方法来获得日期,这是我尝试过的:

    from marshmallow import Schema, fields, pprint
    
    event = {'name': 'foo', 'start': {'date': '2016-06-19', 'time': '18:00'}}
    class EventSchema(Schema):
        name = fields.Str()
        date = fields.Str(load_from='start.date')
    
    
    schema = EventSchema()
    result = schema.load(event)
    pprint(result.data)
    
    4 回复  |  直到 6 年前
        1
  •  20
  •   Jon    6 年前

    你所描述的可以通过 转换* 您的输入数据 预处理* 步虽然公认的答案看起来会这样做, Marshmallow has built-in decorators 让你以我认为更清晰的方式完成这一任务:

    from marshmallow import Schema, pre_load, fields, pprint
    
    event = {'name': 'foo', 'start': {'date': '2016-06-19', 'time': '18:00'}}
    expected = {'name': 'foo', 'date': '2016-06-19'}
    
    
    class EventSchema(Schema):
        name = fields.Str()
        # Marshmallow 2
        date = fields.Str(load_from='date')
        # Marshmallow 3
        date = fields.Str(data_key='date')
    
        @pre_load
        def move_date(self, data):
            """This will alter the data passed to ``load()`` before Marshmallow
            attempts deserialization.
            """
            start = data.pop('start')
            data['date'] = start['date']
            return data
    
    schema = EventSchema()
    result = schema.load(event)
    pprint(result.data)
    
    assert result.data == expected
    

    * 使改变 预处理 是对象建模和数据处理领域的艺术术语。我把它们加粗了,因为知道这些可能会帮助那些成功阅读这个问题的人用谷歌搜索相关问题的答案。

        2
  •  7
  •   Moses Koledoye    8 年前

    您需要创建一个 NestedSchema 并覆盖父模式的 load 方法将嵌套字段附加到父级。指定一个 only 属性,因此 Nested 字段不会获取其所有项:

    class DateTimeSchema(Schema):
        date = fields.Str()
        time = fields.Str()
    
    
    class EventSchema(Schema):
        name = fields.Str()
        date = fields.Nested(DateTimeSchema, load_from='start', only='date')
    
        def load(self, *args, special=None):
            _partial = super(EventSchema, self).load(*args)
    
            # Move special field from Nest to Parent
            if special is not None and special in _partial.data:
                _partial.data[special]  = _partial.data[special].get(special)
            return _partial
    

    并按如下方式设置模式实例:

    event = {'name': 'foo', 'start': {'date': '2016-06-19', 'time': '18:00'}}
    
    schema, special_field = EventSchema(), 'date'
    result = schema.load(event, special=special_field)
    pprint(result.data)
    # {'name': 'foo', 'date': '2016-06-19'}
    

    你总是可以根据自己的口味进行微调。

        3
  •  2
  •   MarredCheese Lionia Vasilev    5 年前

    棉花糖3有 Pluck :

    class DateTimeSchema(Schema):
        date = fields.Str()
        time = fields.Str()
    
    class EventSchema(Schema):
        name = fields.Str()
        date = fields.Pluck(DateTimeSchema, 'date')
    

    documentation for fields.Pluck()

        4
  •  1
  •   Tedpac    3 年前

    鉴于前面的答案有多复杂,我想提供一个非常简单的解决方案(使用 fields.Function ):

    from marshmallow import Schema, fields
    
    class EventSchema(Schema):
        name = fields.Str()
        date = fields.Function(data_key='start',
                               deserialize=lambda start: start['date'])
    
    schema = EventSchema()
    event = {'name': 'foo', 'start': {'date': '2016-06-19', 'time': '18:00'}}
    result = schema.load(event)
    print(result)
    

    结果如预期: {'name': 'foo', 'date': '2016-06-19'} .

    这适用于版本3的 marshmallow .

    推荐文章