Automatic dictionary key resolution with nested sc

2019-06-28 06:39发布

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": "steve@example.com",
#     "friends": ["Mike"]
#   },
#   "Mike": {
#     "name": "Mike",
#     "email": "mike@example.com",
#     "friends": []
# }


deserialized_data = UserSchema().load(result)
pprint(deserialized_data)
# "contacts": {
#   "Steve": {
#     "name": "Steve",
#     "email": "steve@example.com",
#     "friends": [ {"name": "Mike", "email": "mike@example.com"]
#   },
#   "Mike": {
#     "name": "Mike",
#     "email": "mike@example.com",
#     "friends": []
# }

I have also filed an issue on the Marshmallow Github repository.

1条回答
\"骚年 ilove
2楼-- · 2019-06-28 07:06

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": "steve@example.com",
    "friends": ["Mike"]
  },
  "Mike": {
    "name": "Mike",
    "email": "mike@example.com",
    "friends": []
  }
 }
}
"""

deserialized_data = AddressBookSchema().loads(data)
pprint(deserialized_data)

yields:

UnmarshalResult(data={'contacts': {'Steve': {'name': 'Steve', 'email': 'steve@example.com', 'friends': [{'name': 'Mike', 'email': 'mike@example.com', 'friends': []}]}, 'Mike': {'name': 'Mike', 'email': 'mike@example.com', 'friends': []}}}, errors={})
查看更多
登录 后发表回答