I have a Marshmallow schema where an objects use a key to refer to an object that is defined in a dictionary in another part of the structure. I want to have the key automatically resolved when deserializing the object. How can I achieve this effect in Marshmallow in an idiomatic manner?
The workaround for now is to resolve all of the references manually, but this seems clunky, since the declarative nature of Marshmallow should be able to do it for us automatically.
Note that Marshmallow-SQLAlchemy supports this kind of (de-)serialization when columns are declared as relationships" which do this automatically for us, but I want to do it with JSON data.
Here is an example of what I want to achieve, with fields.Relationship
being something that does not exist yet:
class UserSchema(Schema):
name = fields.String()
email = fields.Email()
friends = fields.Relationship('self', path="AddressBook.contacts", many=True)
class AddressBookSchema(Schema):
contacts = nested.Dict(keys=fields.String(), values=fields.Nested(UserSchema))
# ... create ``user`` ...
serialized_data = AddressBookSchema().dump(user)
pprint(serialized_data)
# "contacts": {
# "Steve": {
# "name": "Steve",
# "email": "[email protected]",
# "friends": ["Mike"]
# },
# "Mike": {
# "name": "Mike",
# "email": "[email protected]",
# "friends": []
# }
deserialized_data = UserSchema().load(result)
pprint(deserialized_data)
# "contacts": {
# "Steve": {
# "name": "Steve",
# "email": "[email protected]",
# "friends": [ {"name": "Mike", "email": "[email protected]"]
# },
# "Mike": {
# "name": "Mike",
# "email": "[email protected]",
# "friends": []
# }
I have also filed an issue on the Marshmallow Github repository.
why not simply transfer the intermediate data with a post_load
hook:
class UserSchema(Schema):
name = fields.String()
email = fields.Email()
friends = fields.List(fields.String())
class AddressBookSchema(Schema):
contacts = fields.Dict(keys=fields.String(), values=fields.Nested(UserSchema))
@post_load
def trans_friends(self, item):
for name in item['contacts']:
item['contacts'][name]['friends'] = [item['contacts'][n] for n in item['contacts'][name]['friends']]
data = """
{
"contacts": {
"Steve": {
"name": "Steve",
"email": "[email protected]",
"friends": ["Mike"]
},
"Mike": {
"name": "Mike",
"email": "[email protected]",
"friends": []
}
}
}
"""
deserialized_data = AddressBookSchema().loads(data)
pprint(deserialized_data)
yields:
UnmarshalResult(data={'contacts': {'Steve': {'name': 'Steve', 'email': '[email protected]', 'friends': [{'name': 'Mike', 'email': '[email protected]', 'friends': []}]}, 'Mike': {'name': 'Mike', 'email': '[email protected]', 'friends': []}}}, errors={})
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