'Pydantic - Dynamically create a model with multiple base classes?
From the pydantic docs I understand this:
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'])
However, when I want to create a similar object dynamically (following the section dynamic-model-creation):
# this results in a TypeError
pydantic.create_model("Student_User2", __base__=(User, Student))
I get:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Question: How to dynamically create a class like Student_User
Solution 1:[1]
Your problem is not with pydantic
but with how python handles multiple inheritances. I am assuming in the above code, you created a class which has both the fields of User
as well as Student
, so a better way to do that is
class User(pydantic.BaseModel):
id: int
name: str
class Student(User):
semester: int
class Student_User(Student):
building: str
This gets your job done. So, now if you want to create these models dynamically, you would do
pydantic.create_model("Student_User2", building=(str, ...), __base__=Student)
Obviously, building
is the new model's field, so you can change that as you want
So, the final complete code would look something like this
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)
Solution 2:[2]
Its not the answer to the original question, but if you are like me and all you care about is having a model which holds fields of other models, this should be a solutions.
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, '')},
})
Essentially, we are dynamically creating a new pydantic model and we are setting its fields to be the fields of our other models plus an additional custom field.
Note: OP included these lines in his question:
print(Student_User.__fields__.keys())
#> dict_keys(['semester', 'id', 'name', 'building'])
So, my guess is that his end goal was copying the fields from the other models and having a model created from multiple bases was just a method of achieving it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Dharman |
Solution 2 | OriFl |