2023-03-12

Converting Between Pydantic Models and Dictionaries

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:

python
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:

python
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.

python
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.

python
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.

python
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.

python
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.

python
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.

python
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:

python
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:

python
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.

Ryusei Kakujo

researchgatelinkedingithub

Focusing on data science for mobility

Bench Press 100kg!