Автоматическое разрешение ключей словаря с вложенными схемами с использованием Marshmallow

У меня есть схема Marshmallow, в которой объекты используют ключ для ссылки на объект, определенный в словаре в другой части структуры. Я хочу, чтобы ключ автоматически разрешался при десериализации объекта. Как я могу добиться этого эффекта в Marshmallow в идиоматической манере?

Обходной путь на данный момент состоит в том, чтобы разрешить все ссылки вручную, но это кажется неуклюжим, поскольку декларативный характер Marshmallow должен сделать это за нас автоматически.

Обратите внимание, что Marshmallow-SQLAlchemy поддерживает этот вид (де-)сериализации, когда столбцы объявлены как отношения", которые делают это автоматически для нас, но я хочу сделать это с данными JSON.

Вот пример того, чего я хочу достичь, когда fields.Relationship является чем-то, чего еще не существует:

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": []
# }

Я также зарегистрировал ошибку в репозитории Marshmallow Github.


person cdiggins    schedule 23.08.2018    source источник


Ответы (1)


почему бы просто не передать промежуточные данные с помощью хука post_load :

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)

дает:

UnmarshalResult(data={'contacts': {'Steve': {'name': 'Steve', 'email': '[email protected]', 'friends': [{'name': 'Mike', 'email': '[email protected]', 'friends': []}]}, 'Mike': {'name': 'Mike', 'email': '[email protected]', 'friends': []}}}, errors={})
person georgexsh    schedule 15.10.2018