create_model() factory function for dynamic models
The create_model() factory function creates models dynamically at runtime. It accepts a model name string as the first argument, accepts __base__ keyword argument to specify a parent model class, and accepts field definitions as keyword arguments where each field is a tuple of (type_annotation, default_value).
Dynamic model with inherited validators and computed fields
When using create_model() with __base__ parameter pointing to an original model class, the dynamically created model will inherit validators and computed fields from the parent. Parent fields are overridden by the new field definitions.
Example: make fields optional dynamically
from typing import Annotated
from pydantic import BaseModel, Field, create_model
def make_fields_optional(model_cls: type[BaseModel]) -> type[BaseModel]:
new_fields = {}
for f_name, f_info in model_cls.model_fields.items():
f_dct = f_info.asdict()
new_fields[f_name] = (
Annotated[f_dct['annotation'] | None, *f_dct['metadata'], Field(**f_dct['attributes'])],
None,
)
return create_model(
f'{model_cls.__name__}Optional',
__base__=model_cls,
**new_fields,
)
class Model(BaseModel):
a: Annotated[int, Field(gt=1)]
ModelOptional = make_fields_optional(Model)
m = ModelOptional()
print(m.a) # None
Do not mutate and reuse FieldInfo instances directly
Copying FieldInfo instances, adding defaults, performing mutations, and reusing them as Annotated metadata is not a supported pattern and could break or be deprecated at any point. Instead, use the pattern of reconstructing the annotation by unpacking metadata and calling Field() with attributes.
MISSING sentinel as alternative to None for default values
The experimental MISSING sentinel can be used as an alternative to None for default values when creating dynamic models. Use it by replacing None in both the new annotation and default value.
Reconstructing field annotation with union None type
When dynamically recreating a field annotation, use the union operator (|) to add None to the existing annotation type: f_dct['annotation'] | None, which converts int to int | None, for example.
Redis queue serialization and deserialization example
To use Pydantic with Redis queues, serialize a model instance to JSON using model_dump_json() before pushing to the queue, then deserialize and validate when popping using model_validate_json(). Example: push_to_queue calls user_data.model_dump_json() and r.rpush(QUEUE_NAME, serialized_data). pop_from_queue calls User.model_validate_json(data) to validate the JSON string retrieved from the queue.
RabbitMQ sender script with Pydantic serialization
To send messages to RabbitMQ using Pydantic, create a model, establish a pika connection, declare a queue, and use channel.basic_publish() with the serialized model data. Serialize using model_dump_json() before publishing: channel.basic_publish(exchange='', routing_key=QUEUE_NAME, body=serialized_data).
RabbitMQ receiver script with Pydantic validation
To receive and validate messages from RabbitMQ, define a callback function that takes ch, method, properties, and body parameters. Inside the callback, deserialize and validate the message body using model_validate_json(body), then acknowledge the message with ch.basic_ack(delivery_tag=method.delivery_tag). Use channel.basic_consume(queue=QUEUE_NAME, on_message_callback=process_message) to start consuming.
ARQ background job queue with Pydantic serialization
To use Pydantic with ARQ (Redis-based job queue), define a model and an async process function that validates the input dictionary using model_validate(user_data). Enqueue jobs by serializing the model with model_dump() before passing to redis.enqueue_job('process_user', user1.model_dump()). Define a WorkerSettings class with the functions list and redis_settings.
Basic Pydantic installation with pip
Install Pydantic using pip with the command: pip install pydantic
Install multiple Pydantic optional dependencies
Install multiple optional dependencies together using pip: pip install 'pydantic[email,timezone]' or using uv: uv add 'pydantic[email,timezone]'
Install optional dependencies manually
Optional dependencies can be installed manually with: pip install email-validator tzdata
Install Pydantic from GitHub repository with uv
Install Pydantic directly from the main branch using: uv add 'git+https://github.com/pydantic/pydantic@main' To include optional extras: uv add 'git+https://github.com/pydantic/pydantic@main#egg=pydantic[email,timezone]'
Basic Pydantic installation with uv
Install Pydantic using uv with the command: uv add pydantic
Pydantic core dependencies
Pydantic has four core dependencies: pydantic-core (core validation logic written in Rust), typing-extensions (backport of the standard library typing module), annotated-types (reusable constraint types for use with typing.Annotated), and typing-inspection (runtime typing introspection tools).
Pydantic Python version requirement
Pydantic requires Python 3.10 or later and pip to be installed.
Pydantic installation via conda
Install Pydantic using conda from the conda-forge channel with the command: conda install pydantic -c conda-forge
BaseModel instantiation with keyword arguments
Pydantic BaseModel instances are created by passing external data as keyword arguments to the class constructor.
TypeAdapter with TypedDict example
Example showing TypeAdapter usage with TypedDict:
from datetime import datetime
from typing_extensions import NotRequired, TypedDict
from pydantic import TypeAdapter
class Meeting(TypedDict):
when: datetime
where: bytes
why: NotRequired[str]
meeting_adapter = TypeAdapter(Meeting)
m = meeting_adapter.validate_python(
{'when': '2020-01-01T12:00', 'where': 'home'}
)
print(m)
#> {'when': datetime.datetime(2020, 1, 1, 12, 0), 'where': b'home'}
meeting_adapter.dump_python(m, exclude={'where'})
print(meeting_adapter.json_schema())
"""
{
'properties': {
'when': {'format': 'date-time', 'title': 'When', 'type': 'string'},
'where': {'format': 'binary', 'title': 'Where', 'type': 'string'},
'why': {'title': 'Why', 'type': 'string'},
},
'required': ['when', 'where'],
'title': 'Meeting',
'type': 'object',
}
"""
Four ways to create Pydantic schemas
Pydantic provides four ways to create schemas and perform validation and serialization: 1) BaseModel — Pydantic's own super class with utilities via instance methods, 2) Pydantic dataclasses — wrapper around standard dataclasses with additional validation, 3) TypeAdapter — general way to adapt any type for validation and serialization including TypedDict and NamedTuple, 4) validate_call — decorator to perform validation when calling a function.