Deserialize nested fields in marshmallow

camaya picture camaya · Jun 19, 2016 · Viewed 7.9k times · Source

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)

Answer

Stew picture Stew · Aug 8, 2016

What you describe can be accomplished by transforming* your input data in a pre-processing* step. While the accepted answer looks like it will do that, Marshmallow has built-in decorators to allow you to accomplish this in a way that I think is even clearer:

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

* transform and pre-process are terms of art in the domain of object modeling and data processing. I bolded them because knowing these might help folks who read this question successfully Google for answers to related questions.