With a Pydantic class as follows, I want to transform the foo
field by applying a replace
operation:
from typing import List
from pydantic import BaseModel
class MyModel(BaseModel):
foo: List[str]
my_object = MyModel(foo="hello-there")
my_object.foo = [s.replace("-", "_") for s in my_object.foo]
How can I do the replace
operation right within the class, when the object is created? Without Pydantic I would simply do that within __init(self, foo)
but since Pydantic creates its own __init__
implementation I'm not sure how to proceed exactly.
Here we have the __post_model_init__ dunder method at our disposal to work with the object after instantiation.
from typing import List
from pydantic import BaseModel
class MyModel(BaseModel):
foo: List[str]
def model_post_init(self, __context):
self.foo = [s.replace("-", "_") for s in self.foo]
my_object = MyModel(foo=["hello-there"])
print(my_object)
# Outputs foo=['hello_there']
It seems as you would have to override the basemodels init method, something like this:
from typing import List
from pydantic import BaseModel
class MyModel(BaseModel):
foo: List[str]
def __init__(self, **data):
data["foo"] = [s.replace("-", "_") for s in data["foo"]]
super().__init__(**data)
my_object = MyModel(foo=["hello-there"])
print(my_object)
# Outputs foo=['hello_there']
... or you could also turn it into a pydantic dataclass and use the post init dunder provided by pydantic to do other things upon instantiation. e.g:
from typing import List
from pydantic.dataclasses import dataclass
@dataclass
class MyModel():
foo: List[str]
def __post_init__(self):
self.foo = [s.replace("-", "_") for s in self.foo]
my_object = MyModel(foo=["hello-there"])
print(my_object)
# Outputs foo=['hello_there']
I would personally avoid using the @validator or @field_validator decorators to mutate the object purely based on their naming. Their namings suggests they are meant to be used for validating the object so I would not expect any mutation to happen if i saw it in code.