Converting Pydantic Models to Dictionaries
One of the key features of Pydantic is its ability to convert models to Python native data types, such as dictionaries. This process is straightforward and can be customized to suit specific needs. The primary way to achieve this conversion is by using the .dict()
method available on every Pydantic model instance.
Using .dict() Method
The .dict()
method is a built-in function in Pydantic models that returns a dictionary representation of the model. This method iterates over the model's fields and constructs a dictionary where the keys correspond to the field names and the values to the field values.
Consider the following Pydantic model:
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
email: str
You can create an instance of this model and convert it into a dictionary as follows:
user = User(name='John Doe', age=30, email='john.doe@example.com')
user_dict = user.dict()
print(user_dict)
The output will be a dictionary:
{'name': 'John Doe', 'age': 30, 'email': 'john.doe@example.com'}
Customizing Conversion
The .dict()
method provides several parameters that allow you to customize the resulting dictionary. Here, we will delve into each of these parameters and provide some examples.
include
This parameter allows you to specify a set of fields to include in the output. All other fields will be excluded. The fields are passed as strings in a set.
user_dict = user.dict(include={"name", "email"})
print(user_dict)
{'name': 'John Doe', 'email': 'john.doe@example.com'}
exclude
The exclude
parameter allows you to specify a set of fields to exclude from the output. All other fields will be included. Like include
, the fields are passed as strings in a set.
user_dict = user.dict(exclude={"email"})
print(user_dict)
{'name': 'John Doe', 'age': 30}
by_alias
If set to True
, the by_alias
parameter causes the output dictionary to use the field's alias (if defined) instead of the field's name. This can be useful when you want the dictionary keys to match the external representation of the model, for example, when generating API responses.
from pydantic import BaseModel, Field
class User(BaseModel):
name: str = Field(alias='username')
age: int
email: str
user = User(username='John Doe', age=30, email='john.doe@example.com')
user_dict = user.dict(by_alias=True)
print(user_dict)
{'username': 'John Doe', 'age': 30, 'email': 'john.doe@example.com'}
exclude_unset
If exclude_unset
is set to True
, the output dictionary will not include fields that were not explicitly set when creating the model instance. This can be useful when you want to generate a "sparse" dictionary that only includes fields that have been explicitly assigned.
user = User(name='John Doe')
user_dict = user.dict(exclude_unset=True)
print(user_dict)
{'name': 'John Doe'}
exclude_defaults
Setting exclude_defaults
to True
means that fields which are currently equal to their default values will be excluded from the output. This is useful if you want to create a dictionary that only includes fields which have been explicitly set to a non-default value.
class User(BaseModel):
name: str = 'Default Name'
age: int = 0
email: str = 'default@example.com'
user = User(name='John Doe', age=30, email='john.doe@example.com')
user_dict = user.dict(exclude_defaults=True)
print(user_dict)
{'name': 'John Doe', 'age': 30, 'email': 'john.doe@example.com'}
exclude_none
If exclude_none
is set to True
, any fields with value None
will be excluded from the output. This can be useful when you want to ignore nullable fields that haven't been set.
user = User(name='John Doe', age=None)
user_dict = user.dict(exclude_none=True)
print(user_dict)
{'name': 'John Doe'}
Converting Dictionaries to Pydantic Models
While Pydantic models offer a convenient way to handle and validate data, there will often be times when data is received as a dictionary, especially when dealing with JSON data from APIs or data from other Python libraries. In such cases, we can leverage Pydantic's data parsing capabilities to convert dictionaries into Pydantic models.
Using Pydantic Model's Constructor
One of the most straightforward ways to convert a dictionary into a Pydantic model is by using the model's constructor. The keys in the dictionary should correspond to the attributes defined in the Pydantic model.
Using the User
model defined in the previous chapter, let's create a dictionary and convert it to a Pydantic model:
user_dict = {'name': 'John Doe', 'age': 30, 'email': 'john.doe@example.com'}
# Convert dictionary to Pydantic model
user = User(**user_dict)
print(user)
The output will be a Pydantic model:
User(name='John Doe', age=30, email='john.doe@example.com')
Notice the use of **
before user_dict
in the model's constructor. This operator is known as the dictionary unpacking operator, which passes the keys and values in the dictionary as keyword arguments to the function.
Handling Validation Errors
One key feature of Pydantic models is their built-in data validation capabilities. When creating a Pydantic model from a dictionary, Pydantic validates the data against the model's type hints. If the data does not match the expected types or does not pass other custom validations, Pydantic raises a ValidationError
.
For instance, let's attempt to create a User
model with incorrect data types:
incorrect_user_dict = {'name': 'John Doe', 'age': '30', 'email': 'john.doe@example.com'}
try:
user = User(**incorrect_user_dict)
except ValidationError as e:
print(e)
In this case, Pydantic raises a ValidationError
indicating that the age
field must be an integer:
1 validation error for User
age
value is not a valid integer (type=type_error.integer)
This error message tells you exactly what went wrong, enabling you to catch and handle data validation errors effectively in your code.