This succinct, practical article is about the model_post_init()
method in Pydantic. We’ll learn the fundamentals of the method and then walk through a few examples of using it in practice. Without any further ado; let’s begin!
The Fundamentals
model_post_init()
is a special method that gets called automatically after the initialization of a Pydantic model. The purpose of the model_post_init()
method is to allow custom logic to be executed after the model initialization. This can be useful for performing additional validation, transformation, or computation on the model fields or attributes.
General syntax:
class MyModel(BaseModel):
# define model fields and validators here
def model_post_init(self, __context: Any) -> None:
# write custom logic here
The method takes one parameter, __context
, which is an instance of pydantic.context.Context
class. This class provides access to some useful information about the model initialization, such as the input data, the config, and the fields1. The method does not return any value, but it can modify the model instance in place.
Enough of words. Now it’s time to get our hands dirty by writing some code.
Examples
Example 1: Basic
This example shows the basic usage of the model_post_init()
method. What we’re doing here is to define a User
model with a model_post_init()
method that prints a message to the console when a User
object is created.
The code:
# This example uses Pydantic 2.4
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
def model_post_init(self, *args, **kwargs):
print(f"User {self.name} has been created.")
user = User(name="Innocent Wolf", age=225)
Output:
User Innocent Wolf has been created.
Example 2: Validation in model_post_init()
This example demonstrates the way to perform additional validation in the model_post_init() method. We’ll raise a ValueError
in the model_post_init()
method if the user’s age is less than 18.
# This example uses Pydantic 2.4
from pydantic import BaseModel, ValidationError
class User(BaseModel):
name: str
age: int
def model_post_init(self, *args, **kwargs):
if self.age < 18:
raise ValueError("User must be at least 18 years old")
try:
user = User(name="Cute Puppy", age=2)
except ValueError as e:
print(str(e))
Output:
1 validation error for User
Value error, User must be at least 18 years old [type=value_error, input_value={'name': 'Cute Puppy', 'age': 2}, input_type=dict]
Example 3: Modifying Model Data in model_post_init()
This example shows how to modify the data of a Pydantic model in the model_post_init()
method. We’ll use it to hash the user’s password after the model has been initialized.
# This example uses Pydantic 2.4
from pydantic import BaseModel, ValidationError, field_validator
class User(BaseModel):
name: str
age: int
password: str
@field_validator("password")
def validate_password(cls, password):
if len(password) < 8:
raise ValueError("Password must be at least 8 characters")
return password
def model_post_init(self, *args, **kwargs):
self.password = self.hash_password(self.password)
@staticmethod
def hash_password(password):
# This is a simple hashing for demonstration purposes.
# In a real application, you'd want to use a secure hashing algorithm.
return "".join(reversed(password))
user = User(name="John Doe", age=35, password="123456789")
print(user.password)
Output:
987654321
Example 4: Setting a default value based on another field
In this example, we want to create a model that represents a person with a name and an email. We want the email field to be optional, but if it is not provided, we want to set a default value based on the name field. For example, if the name is Cristiano Ronaldo
, the default email should be [email protected]
. We can use the model_post_init()
method to achieve this:
# This example uses Pydantic 2.4
from pydantic import BaseModel, EmailStr
class Person(BaseModel):
name: str
email: EmailStr = None
def model_post_init(self, __context) -> None:
# if email is not provided, set a default value based on name
if self.email is None:
self.email = f"{self.name.lower().replace(' ', '_')}@slingacademy.com"
# test the model
p1 = Person(name="Cristiano Ronaldo")
print(p1)
p2 = Person(name="Lionel Messi", email="[email protected]")
print(p2)
Output:
name='Cristiano Ronaldo' email='[email protected]'
name='Lionel Messi' email='[email protected]'
Conclusion
The model_post_init()
method is a useful and powerful feature of Pydantic. It allows programmers to customize the model behavior and logic after the initialization, which can be handy for various scenarios. However, you should use it with caution and test it thoroughly, as it can potentially modify the model instance in unexpected ways or raise errors that are not caught by the validators.