从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
的类
这不是原始问题的答案,但如果您像我一样并且您关心的只是拥有一个包含其他模型字段的模型,那么这应该是一个解决方案。
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'])
所以,我的猜测是,他的最终目标是复制其他模型中的字段,并且从多个基础创建模型只是实现它的一种方法。
截至
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'])
你的问题不在于
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)
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
这将在没有警告的情况下工作。