python - 为大型嵌套父级、子级复杂 JSON 文件创建 Pydantic 模型

标签 python fastapi pydantic

我有一个 JSON 文件,其中包含许多具有父子关系的对象。这就是 JSON 在高层次上的样子。

{
    "objectType1": {
        "objectType1ID1": {
            "parent": {},
            "children": [{"id":"objectType2ID2"}],
            "properties": {}
        },
        "objectType1ID2": {
            "parent": {},
            "children": [{}],
            "properties": {}
        }
    },
    "objectType2": {
        "objectType2ID1": {
            "parent": {},
            "children": [],
            "properties": {}
        },
        "objectType2ID2": {
            "parent": {"id":"objectType1ID1"},
            "children": [],
            "properties": {}
        }
    }
}

第一级键包含各种类型的对象,然后在每种类型中都有任意数量的该类型的对象,其中包含父级、子级(列表)和属性键。每个对象在列表中最多可以有一个父对象或多个子对象。

我正在尝试为这个结构构建一个 Pydantic 模型。以下是我到目前为止所掌握的内容,但我是 Pydantic 的新手,我陷入了困境。

from pydantic import BaseModel
from typing import List, Optional

class ObjectParent(BaseModel):
    id: Optional[str]

class ObjectChild(BaseModel):
    id: Optional[str]

class Properties(BaseModel):
    name: Optional[str]
    description: Optional[str]


class Object(BaseModel):
    id: str
    parent: Optional['ObjectParent'] = None
    children: List['ObjectChild'] = []
    properties: Properties

最佳答案

我尝试解决这个问题,需要一些 pydantic 的高级用法。

TLDR

让我们切入正题 -> 这是您想要使用的功能:

from typing import Dict
from pydantic import BaseModel

class JsonObject(BaseModel):
    __root__: Dict[str, Dict[str, int]]

# Allows instantiating by parsing an object:
my_obj = JsonObject.parse_obj({
    "a": {"one": 1, "two": 2},
    "b": {"three": 3},
    "c": {}
})

>> my_obj.__root__
{'a': {'one': 1, 'two': 2}, 'b': {'three': 3}, 'c': {}}

现在让我们深入探讨

让我们尝试在嵌套结构的深度建模单个“根”对象:

"objectType1ID1": {
  "parent": {},
  "children": [
   {
    "id": "objectType2ID2"
   }
  ],
  "properties": {}
 }

以下 pydantic 模型应该可以工作:

class AssociatedObject(BaseModel):
    """
    Represents an associated object, whether
    that is a parent or a child.
    """
    id: Optional[str]


class ObjectProperties(BaseModel):
    name: Optional[str]
    description: Optional[str]


class BaseObject(BaseModel):
    """
    Represents an object at the furthest depth
    of the nested structure
    """
    parent: AssociatedObject = AssociatedObject()
    children: List[AssociatedObject] = [AssociatedObject()]
    properties: ObjectProperties = ObjectProperties()

如果我们用空值实例化,我们应该得到 json 对象中表示的内容:

>> BaseObject().dict(exclude_none=True)
{'parent': {}, 'children': [{}], 'properties': {}}

现在是最困难的部分 - 如何定义父键?

创建一个类,可以将我们的对象及其类型名称(objectType1ID1)存储为动态字典:

from typing import Dict

class JsonObject(BaseModel):
    __root__: Dict[str, Dict[str, BaseObject]]

如果我们实例化,我们会看到它按预期工作:

json_object = JsonObject(__root__=
    {
        "objectType1": {
            "objectType1ID1": BaseObject(parent=AssociatedObject(id="objectType2ID2")),
            "objectType1ID2": BaseObject()
        },
        "objectType2": {
            "objectType2ID1": BaseObject(),
            "objectType2ID2": BaseObject(parent=AssociatedObject(id="objectType1ID1"))
        }
    }
)

parent_object.dict(exclude_none=True)['__root__']

{
 "objectType1": {
  "objectType1ID1": {
   "parent": {
    "id": "objectType2ID2"
   },
   "children": [
    {}
   ],
   "properties": {}
  },
  "objectType1ID2": {
   "parent": {},
   "children": [
    {}
   ],
   "properties": {}
  }
 },
 "objectType2": {
  "objectType2ID1": {
   "parent": {},
   "children": [
    {}
   ],
   "properties": {}
  },
  "objectType2ID2": {
   "parent": {
    "id": "objectType1ID1"
   },
   "children": [
    {}
   ],
   "properties": {}
  }
 }
}

最后:您现在可以成功解析初始嵌套对象:

# Object provided in original Q
my_initial_object = {
    "objectType1": {
        "objectType1ID1": {
            "parent": {},
            "children": [{"id":"objectType2ID2"}],
            "properties": {}
        },
        "objectType1ID2": {
            "parent": {},
            "children": [{}],
            "properties": {}
        }
    },
    "objectType2": {
        "objectType2ID1": {
            "parent": {},
            "children": [],
            "properties": {}
        },
        "objectType2ID2": {
            "parent": {"id":"objectType1ID1"},
            "children": [],
            "properties": {}
        }
    }
}

# This works
my_json_object = JsonObject.parse_obj(my_initial_object)

关于python - 为大型嵌套父级、子级复杂 JSON 文件创建 Pydantic 模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74791067/

相关文章:

python - 我可以让 FastAPI 端点接收 json 或文件吗

python-3.x - 如何更改 Pydantic 默认 __root__ 示例

python - 如何将自定义装饰器添加到FastAPI路由?

python - 使用 Pydantic 将每个字段设为可选

Python,并行运行命令行工具

python - PyCrypto 和 GMP 库未找到错误 [Mac OS 10.6.3]

python - 使用快速傅里叶变换分析音频

python - Mixins、多重继承、构造函数和数据

python - 在 Python 中异步编写 CSV 文件

python - 将 fastapi 与 plotly.dash 结合并将 token 依赖项添加为 auth 的问题