Как с помощью mongoengine + marshmallow описать самовложенные модели?
Есть документ в MongoDB:
{
"_id": {
"$oid": "5e7a12dbf89bd64d88f73750"
},
"type": "_t",
"value": "Proj",
"elements": [
{
"type": "_p",
"value": "Glob",
"elements": [
{
"type": "_v",
"value": "3qm21lOV13_vWp0uTxo2z8"
}
]
},
{
"type": "_p",
"value": "Owner",
"elements": [
{
"type": "_t",
"value": "OH",
"attributes": {
"nil": true,
"ref": {
"$oid": "5e77c8055e59b043d4acdf10"
}
}
}
]
},
{
"type": "_p",
"value": "Count",
"elements": [
{
"type": "_v",
"value": 500.0
}
]
}
]
}
Как видно, имеет место самовложение, в списке elements могут быть объекты структурно идентичные корневому. Вопрос, как правильно описать модель для подобного рода структуры и как потом это сериализовать в JSON с помощью marshmallow?
Я пробую создать модели и зациклить вложенную на саму себя:
class EmbeddedElement(me.EmbeddedDocument):
type = me.StringField(required=True, max_length=16)
value = me.DynamicField()
attributes = me.DictField()
elements = me.EmbeddedDocumentListField(document_type="EmbeddedElement")
class Element(me.Document):
type = me.StringField(required=True, max_length=16)
value = me.DynamicField()
attributes = me.DictField()
elements = me.EmbeddedDocumentListField(document_type=EmbeddedElement)
meta = {'collection': 'projects'}
Далее описываю схему marshmallow:
class TempSchema(Schema):
id = fields.String()
ref = fields.String()
class Meta:
model = Element
fields = ('id', 'type', 'value', 'attributes', 'elements', 'ref', 'nil')
При попытке сделать:
e = Element.objects.skip(offset).limit(per_page)
temp_schema.dump(e)
Вылетает ошибка - TypeError: Object of type EmbeddedElement is not JSON serializable.
Как с подобным бороться? Полагаю, что дело не только в невозможности сериализовать EmbeddedElement, правильно ли вообще так описывать самовложенные модели, если нет, то как правильно?
Ответы (1 шт):
Ответ: Да, такое определение моделей будет работать, хотя в изящности метода я сильно сомневаюсь. Для того, что бы всё корректно сериализовалось, следует добавить схему для вложенного объекта attributes:
class AttributeSchema(Schema):
ref = fields.String()
class Meta:
fields: Tuple[str] = ('nil', 'ref', 'cType')
Таким образом, мы определим как сериализовать ObjectId во вложенных объектах.
Так же необходимо в уже существующие схемы добавить списки с вложенными схемами:
class EmbeddedElementSchema(Schema):
id = fields.String()
elements = fields.List(fields.Nested('EmbeddedElementSchema'))
attributes = fields.Nested(AttributeSchema)
class Meta:
fields = ('id', 'type', 'value', 'attributes', 'elements')
class ElementSchema(EmbeddedElementSchema):
class Meta:
fields = ('id', 'type', 'value', 'attributes', 'elements')
И voilà, можно подавать.