Search code examples
pythontransformationpreprocessormarshmallow

Deserialize nested fields in marshmallow


I'm consuming an API that returns something like:

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

And I want to desearialize it with marshmallow to get only the name and the start date, so the desired result would be the following:

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

But I haven't found any way to get the date, this what I have tried:

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)

Solution

  • You will need to create a NestedSchema for the nested dictionary, and overwrite your parent schema's load method to append the nested field to parent. Specify a only attribute so the Nested field does not fetch all of its items:

    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
    

    And setting up your schema instance like so:

    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'}
    

    You can always fine tune to your taste.