【问题标题】:Mongo Embedded Document is not JSON Serializable - PythonMongo 嵌入式文档不是 JSON 可序列化的 - Python
【发布时间】:2020-08-30 13:15:31
【问题描述】:

我目前正在将 Graphene 与 MongoEngine 一起使用。 mongo db架构如下

class DocumentAModel(Document):
    id = StringField(required=True)
    documentB = MapField(EmbeddedDocumentField(DocumentBModel)

class DocumentBModel(EmbeddedDocument):
    id = StringField(required=True)
    value = IntField()

一个示例文档A如下

{
    id: "id_1",
    documentB: {
        0: {
            id: "b_1",
            value: 1
        },
        1: {
            id: "b_2",
            value: 11
        }
    }

相应地,它们的石墨烯类型是

class DocumentB(MongoengineObjectType):
    class Meta:
        model = DocumentBModel

class DocumentA(MongoengineObjectType):
    class Meta:
        model = DocumentAModel

最后,查询如下所示

class Query(graphene.ObjectType):
    all_document_a = graphene.List(DocumentA)

    def resolve_all_document_a(self, info):
        return list(DocumentAModel.objects.all())

但是,当我查询 allDocumentA 以获取文档 B 时,我得到了错误

DocumentBModel 类型的对象不是 JSON 可序列化的

我不确定将文档 B 编组到 json 的位置。

如果我将 DocumentB 从 MapField(EmbeddedDocumentField(DocumentBModel) 更改为 DictField(),它可以正常工作。但是有没有办法使用 MapField?

谢谢

【问题讨论】:

  • MapField 与 DictField 类似,只是每一项的“值”必须与指定的字段类型匹配。
  • 是的,我想强制该值为 DocumentB 类型
  • 有同样的问题。有进展吗?
  • 是的,我认为问题在于 graphql 要求响应对象具有明确的结构。将字典或地图作为属性“混淆”graphql。在上面的示例中,查询可能是 query { documentA { id documentB { 0 { id value } 1 { id value } } } } 但 documentB 没有任何属性 0 和 1。所以它只需要是一个字典列表。希望有帮助

标签: json python-3.x mongoengine graphene-python


【解决方案1】:

MapField类似于DictField,只是每个item的“value”必须匹配指定的字段类型,key必须是String类型。 因此,在您的情况下,DocumentAModel documentB 字段是 MapField,值类型是 DocumentBModel。因此,对于 DocumentBModel,您需要提供 id 和 value 字段。您正在使用石墨烯创建它,但对于普通(REST)DRF APIGraphQL API,模型映射将是相同的。 MapField 有一些验证,比如 key 应该是 String 类型,value 应该是你在模型中提到的类型,但是对于 Dictfield,它不需要这样的类型验证,它只是普通的 Python 字典字段

检查代码 sn-p。并根据需要更改 Graphene 查询和架构。

检查以下代码:

class DocumentBModel(fields.EmbeddedDocument):
    id = fields.StringField(required=True)
    value = fields.IntField()


class DocumentAModel(Document):
    name = fields.StringField(required=True)
    documentB = fields.MapField(fields.EmbeddedDocumentField(DocumentBModel))
Django 外壳
$ python manage.py shell
>>>
>>> B_obj1 = DocumentBModel(**{'id': 'b_1', 'value': 1})
>>> B_obj2 = DocumentBModel(**{'id': 'b_2', 'value': 2})

>>> data_obj = DocumentAModel.objects.create(**{"name":"akash", "documentB":{"0":B_obj1, "1":B_obj2}})
>>> data_obj._data
{'id': ObjectId('5ebd1d2cf549becd5a462924'), 'name': 'akash', 'documentB': {'0': <DocumentBModel: DocumentBModel object>, '1': <DocumentBModel: DocumentBModel object
>}}

数据库条目:

{
    "_id" : ObjectId("5ebd1d2cf549becd5a462924"),
    "name" : "akash",
    "documentB" : {
        "0" : {
            "id" : "b_1",
            "value" : 1
        },
        "1" : {
            "id" : "b_2",
            "value" : 2
        }
    }
}

【讨论】:

  • 如果我遗漏了什么,我很抱歉。但是,当我通过 python 脚本执行此操作时,我能够创建/读取文档 A。当我使用 GraphQL 请求它时会弹出 JSON Serializable 错误,这需要将响应编组为 JSON
  • 您在 DocumentBModel 中提到了 value 字段,并且在检索 mongo 文档中的 count 字段时,这会给您带来冲突。作为 JSON 序列化程序错误。因此,删除集合并使用具有适当值的 GraphQL 创建新集合。
  • 哦,抱歉。这是一个问题输入错误。已更新问题。同样的错误
  • mapfield需要的key应该是String数据类型...试着把它从int改成string。
  • 还是不行。得到与 DocumentB is not JSON Serializable 相同的错误
【解决方案2】:

我认为问题在于 graphql 要求响应对象具有明确的结构。将 dict 或 map 作为属性“混淆”graphql。

在上面的例子中,查询可以是

query {
    documentA {
        id
        documentB {
            0 {
                id
                value
            }
            1 {
                id
                value
            }
        }
    }
}

但是 documentB 没有任何属性 0 和 1。所以它必须是一个字典列表。在这种情况下,查询将变为

query {
    documentA {
        id
        documentB {
            id
            value
        }
    }
}

【讨论】:

    猜你喜欢
    • 2020-07-16
    • 1970-01-01
    • 2015-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多