How to serialize Pydantic models into JSON

Updated: December 14, 2023 By: Frienzied Flame Post a comment

In today’s digital era, data is king. One of the primary challenges for developers is to effectively manage and manipulate this data. In the realm of Python, the Pydantic library has emerged as a powerful tool, specifically for data validation and serialization. This article aims to unravel the intricacies of Pydantic, focusing on different methods to serialize Pydantic models.

Delving into Pydantic

Pydantic is a data validation library in Python that leverages Python type annotations to ensure accurate data parsing. It encourages full-fledged data validation by using Python type annotations in the class definition.

from pydantic import BaseModel

class User(BaseModel):
    id: int
    username: str

The code snippet above illustrates a simple Pydantic model named ‘User’ with an integer field ‘id’ and a string field ‘username’.

Pydantic Serialization: A Primer

In the context of Pydantic, serialization involves transforming a Pydantic model into a less structured form, typically a dictionary or a JSON-encoded string. This process is commonly referred to as “dumping” in Pydantic parlance.

Model Serialization to Dictionary

Utilizing the built-in model_dump() method is the most basic way to serialize a Pydantic model into a dictionary.

Steps:

  1. Define your Pydantic model.
  2. Initialize your model with data.
  3. Use the model_dump() method to serialize the model into a dictionary.

Example:

from pydantic import BaseModel


class User(BaseModel):
    id: int
    username: str


user = User(id=1, username="john_doe")
serialized_user = user.model_dump()

print(serialized_user)
# Output: {'id': 1, 'username': 'john_doe'}

The model_dump() method offers a straightforward and intuitive way to serialize Pydantic models. However, it only provides a dictionary representation of the model and doesn’t give a JSON-encoded string.

Model Serialization to JSON

Pydantic also offers a method, model_dump_json(), to serialize a model directly into a JSON-encoded string.

The steps to follow:

  1. Define your Pydantic model.
  2. Initialize your model with data.
  3. Use the model_dump_json() method to serialize the model into a JSON string.

Example:

from pydantic import BaseModel

class User(BaseModel):
    id: int
    username: str

user = User(id=1, username='john_doe')
serialized_user = user.model_dump_json()

print(serialized_user)
# Output: '{"id": 1, "username": "john_doe"}'

While model_dump_json() offers a JSON-encoded string, making it more suitable for data exchange between a server and a client, it might not be the most efficient method for internal data manipulation within your application.

Custom Serializers in Pydantic

Pydantic allows customization of the serialization process by providing decorators: @field_serializer and @model_serializer, which can be used to define custom serialization logic for specific fields or the entire model.

Steps:

  1. Define your Pydantic model.
  2. Add the @field_serializer or @model_serializer decorator to a function in your model.
  3. Define your custom serialization logic within the function.
  4. Serialize your model using model_dump() or model_dump_json().

Example:

from pydantic import BaseModel, field_serializer, model_serializer
from datetime import datetime


class User(BaseModel):
    id: int
    username: str
    created_at: datetime

    @field_serializer("created_at")
    def serialize_created_at(self, dt: datetime, _info):
        return dt.strftime("%Y-%m-%d %H:%M:%S")


user = User(id=1, username="john_doe", created_at=datetime.now())
serialized_user = user.model_dump()

print(serialized_user)
# Output: {'id': 1, 'username': 'john_doe', 'created_at': '2022-03-25 12:34:56'}

Custom serializers offer flexibility in controlling how the model is serialized. However, they require more complex implementation and might not be necessary for simple use cases.

Conclusion

Pydantic offers a rich set of tools for model serialization, from straightforward techniques to more complex, customizable methods. Understanding these methods and their trade-offs is essential for effective data handling in Python applications. Whether you’re dealing with internal data manipulation or server-client data exchange, Pydantic has got you covered.