I'm a little new to tinkering with class inheritance in python, particularly when it comes down to using class attributes. In this case I am using a class attribute to change an argument in pydantic's Field()
function. This wouldn't be too hard to do if my class contained it's own constructor, however, my class User1
is inheriting this from pydantic's BaseModel
.
The idea is that I would like to be able to change the class attribute prior to creating the instance.
Please see some example code below:
from pydantic import Basemodel, Field
class User1(BaseModel):
_set_ge = None # create class attribute
item: float = Field(..., ge=_set_ge)
# avoid overriding BaseModel's __init__
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
User1._set_ge = 0 # setting the class attribute to a new value
instance = User1(item=-1)
print(instance) # item=-1.0
When creating the instance using instance = User1(item=-1)
I would expect a validation error to be thrown, but it instead passes validation and simply returns the item
value.
If I had my own constructor there would be little issue in changing the _set_ge
, but as User1
inheriting this constructor from BaseModel
, things are a little more complicated.
The eventual aim is to add this class to a fastapi
endpoint as follows:
from fastapi import Fastapi
from schemas import User1
class NewUser1(User1):
pass
NewUser1._set_ge = 0
@app.post("/")
def endpoint(request: NewUser1):
return User1.item
To reduce code duplication, I aimed to use this method to easily change Field()
arguments. If there is a better way, I'd be glad to consider that too.
This question is quite closely related to this unanswered one.
CodePudding user response:
In the end, the @validator
proposal by @hernán-alarcón is probably the best way to do this. For example:
from pydantic import Basemodel, Field
from typing import ClassVar
class User(BaseModel):
_set_ge = ClassVar[float] # added the ClassVar typing to make clearer, but the underscore should be sufficient
item: float = Field(...)
@validator('item')
def limits(cls, v):
limit_number = cls._set_ge
if v >= limit_number:
return v
else:
raise NumberNotGeError(limit_value=limit_number)
class User1(User)
_set_ge = 0 # setting the class attribute to a new value
instance = User1(item=-1) # raises the error