【问题标题】:Pydantic Model Structure for Largely Similar Objects?非常相似的对象的 Pydantic 模型结构?
【发布时间】:2022-10-04 17:52:08
【问题描述】:

我想知道是否有人可以建议一种更好的方法来为这种情况建立 Pydantic 模型?

我正在使用的数据集(JSON)在整个过程中几乎都是相同的结构,但只有在树的最低级别有一些差异。 IE:

// data.json
{
    "FirstItem": {
        "Name": "first item",
        "Data": {
            "attr_1": "a",
            "attr_2": "b"
        }
    },
    "SecondItem": {
        "Name": "second item",
        "Data": {
            "attr_3": "d",
            "attr_4": "e"
        }
    },
    ...
}

所以我想知道,是否有一种建议的方法来构建使用标准“项目”的 Pydantic 模型(在这种情况下,它将具有“名称”和“数据”),然后更改案例中的“数据”-个案基础?

我有一个工作示例,但感觉很冗长?

工作示例:

from pydantic import BaseModel

class FirstItemData(BaseModel):
    attr_1: str
    attr_2: str

class FirstItem(BaseModel):
    Name: str
    Data: FirstItemData # <--- The unique part

class SecondItemData(BaseModel):
    attr_3: str
    attr_4: str

class SecondItem(BaseModel):
    Name: str
    Data: SecondItemData

class Example(BaseModel):
    FirstItem: FirstItem
    SecondItem: SecondItem

o = Example.parse_file("data.json")

以上工作,但感觉每次都构建项目“持有人”(带有“名称”和“数据”的部分)是多余的?有没有办法指定一个通用的“容器”结构,然后换掉“数据”?比如:

class GenericContainer(BaseModel):
    Name: str
    Data: ????

class Example(BaseModel):
    FirstItem: GenericContainer(Data = FirstItemData)
    SecondItem: GenericContainer(Data = SecondItemData)

或类似的东西?在这种情况下,我有几十个这些独特的“项目”(仅在它们的“数据”部分是唯一的)并且为每个创建 2 个类似乎不正确?可以?

我确实意识到使用类型Dict 代替详细的“数据”确实可以加载数据,但它是以字典而不是对象的形式出现的,这在这种情况下并不理想。

非常感谢任何想法或建议。谢谢!

【问题讨论】:

标签: python json pydantic


【解决方案1】:

根据 Hernán Alarcón 的评论,我想尝试 我相信这应该有效。也许它对某人有用。

from pydantic.generics import BaseModel, GenericModel
from typing import Generic, TypeVar, Optional

class FirstItemData(BaseModel):
    attr_1: str
    attr_2: str
class SecondItemData(BaseModel):
    attr_3: str
    attr_4: str
TypeX = TypeVar('TypeX')
class GenericContainer(GenericModel, Generic[TypeX]):
    Name: str
    Data: TypeX
class ItemBag(BaseModel):
    FirstItem: Optional[GenericContainer[FirstItemData]]
    SecondItem: Optional[GenericContainer[SecondItemData]]

# some tests
one_bag = ItemBag(FirstItem = {"Name":"My first item", "Data":{"attr_1":"test1", "attr_2":"test2"}})
another_bag = ItemBag(FirstItem = {"Name":"My first item", "Data":{"attr_1":"test1", "attr_2":"test2"}}, SecondItem = {"Name":"My first item", "Data":{"attr_3":"test3", "attr_4":"test4"}})
# failing tests to slightly check validation
one_failing_bag = ItemBag(FirstItem = {"Name":"My first item", "Data":{"attr_3":"test1", "attr_42":"test2"}})
another_failing_bag = ItemBag(SecondItem = {"Name":"My second item", "Data":{"attr_3":"test3", "attr_42":"test2"}})

# the parsing way
parsed_bag = ItemBag.parse_obj({"FirstItem":{"Name":"My first item", "Data":{"attr_1":"test1", "attr_2":"test2"}}, "SecondItem": {"Name":"My first item", "Data":{"attr_3":"test3", "attr_4":"test4"}}})

所以它有效, 但我不确定我会选择通用性还是可读性。

【讨论】:

    猜你喜欢
    • 2021-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多