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)
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.
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.
Marshmallow 3 has 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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With