Pydantic - 动态创建具有多个基类的模型?

问题描述 投票:0回答:4

pydantic文档我明白这一点:

import pydantic

class User(pydantic.BaseModel):
    id: int
    name: str

class Student(pydantic.BaseModel):
    semester: int

# this works as expected
class Student_User(User, Student):
    building: str

print(Student_User.__fields__.keys())
#> dict_keys(['semester', 'id', 'name', 'building'])

但是,当我想动态创建类似的对象时(遵循动态模型创建部分):

# this results in a TypeError
pydantic.create_model("Student_User2", __base__=(User, Student))

我得到:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

问题:如何动态创建类似

Student_User

的类
python multiple-inheritance pydantic
4个回答
6
投票

这不是原始问题的答案,但如果您像我一样并且您关心的只是拥有一个包含其他模型字段的模型,那么这应该是一个解决方案。

Student_User = pydantic.create_model("Student_User", **{
    **{key: (value.type_, value.default) for key, value in User.__fields__.items()},
    **{key: (value.type_, value.default) for key, value in Student.__fields__.items()},
    **{"building": (str, '')},
})

本质上,我们正在动态创建一个新的 pydantic 模型,并将其字段设置为其他模型的字段加上一个额外的自定义字段。

注意: OP 在他的问题中包含了这些行:

print(Student_User.__fields__.keys())
#> dict_keys(['semester', 'id', 'name', 'building'])

所以,我的猜测是,他的最终目标是复制其他模型中的字段,并且从多个基础创建模型只是实现它的一种方法。


5
投票

截至

pydantic==1.9.2

Student_User2 = pydantic.create_model("Student_User2", __base__=(User, Student), building=(str, ...))

运行成功并且

print(Student_User2.__fields__.keys())

退货

dict_keys(['semester', 'id', 'name', 'building'])

3
投票

你的问题不在于

pydantic
,而在于python如何处理多重继承。我假设在上面的代码中,您创建了一个具有
User
Student
字段的类,因此更好的方法是

class User(pydantic.BaseModel):
    id: int
    name: str

class Student(User):
    semester: int

class Student_User(Student):
    building: str

这样你的工作就完成了。所以,现在如果你想动态创建这些模型,你可以这样做

pydantic.create_model("Student_User2", building=(str, ...), __base__=Student)

显然,

building
是新模型的字段,因此您可以根据需要更改它

所以,最终的完整代码看起来像这样

import pydantic

class User(pydantic.BaseModel):
    id: int
    name: str

class Student(User):
    semester: int

class Student_User(Student):
    building: str

print(Student_User.__fields__.keys())

model = pydantic.create_model("Student_User2", building=(str, ...), __base__=Student)

0
投票
def merge_models(name: str, *models: Iterable[BaseModel]) -> BaseModel:

    fields = {}
    for model in models:
        f = {k: (v.annotation, v) for k, v in model.model_fields.items()}
        fields.update(f)
    return pydantic.create_model(name, **fields)

class Student_User(merge_models("Student_User_Base",User, Student)):
    building: str

这将在没有警告的情况下工作。

© www.soinside.com 2019 - 2024. All rights reserved.