Skip to main content

Collections & Mappings

Pydantic provides extensive support for validating aggregate data structures like lists, sets, tuples, and dictionaries. You can enforce constraints on the collection itself (such as length) as well as on the individual items within it.

Handling Top-Level Collections

When your data is a single collection rather than a set of fields, use RootModel. This allows you to treat a list or dictionary as the primary value of the model, accessible via the .root attribute.

from pydantic import RootModel

class UserList(RootModel):
root: list[str]

# Initialize with a list directly
users = UserList(['alice', 'bob'])
print(users.root)
# > ['alice', 'bob']

# Validation still applies to the items
from pydantic import ValidationError
try:
UserList(['alice', 123])
except ValidationError as e:
print(e.errors())

Constraining Collection Size

The preferred way to add constraints like min_length or max_length to a collection is using Annotated with Field. This pattern is recommended over legacy constrained types for better compatibility with static analysis tools.

from typing import Annotated
from pydantic import BaseModel, Field

class Gallery(BaseModel):
# A list that must have between 1 and 5 items
tags: Annotated[list[str], Field(min_length=1, max_length=5)]

# A dictionary with size constraints
metadata: Annotated[dict[str, str], Field(max_length=10)]

# Valid
g = Gallery(tags=['nature'], metadata={'author': 'pydantic'})

Legacy Constrained Types

Pydantic provides convenience functions like conlist, conset, and confrozenset which return Annotated types with length constraints.

from pydantic import BaseModel, conlist, conset

class LegacyModel(BaseModel):
# Equivalent to Annotated[list[int], Field(max_length=10)]
scores: conlist(int, max_length=10) = []

# Sets automatically handle uniqueness and support length constraints
unique_ids: conset(int, min_length=1)

[!WARNING] The unique_items parameter for conlist was removed in Pydantic V2. Use set or conset if you require unique items.

Item-Level Validation Control

You can control how Pydantic handles validation errors for individual items within a collection using specialized annotations found in pydantic.types.

Skipping Invalid Items with OnErrorOmit

Use OnErrorOmit to silently discard items that fail validation instead of raising a ValidationError for the entire collection. This is useful for cleaning "dirty" data.

from pydantic import BaseModel, OnErrorOmit

class DataCleaner(BaseModel):
# Only valid integers will be kept in the list
numbers: list[OnErrorOmit[int]]

m = DataCleaner(numbers=[1, 'invalid', 2, 3.5, '4'])
# 3.5 is coerced to 3, '4' to 4, 'invalid' is omitted
print(m.numbers)
# > [1, 2, 3, 4]

Performance Optimization with FailFast

For large collections where you only need to know if the data is valid or not, FailFast stops validation at the first error encountered, improving performance by avoiding unnecessary checks on subsequent items.

from typing import Annotated
from pydantic import BaseModel, FailFast, ValidationError

class LargeBatch(BaseModel):
data: Annotated[list[int], FailFast()]

try:
# Validation stops at 'a', ignoring the rest of the list
LargeBatch(data=[1, 2, 'a', 4, 5, 'b'])
except ValidationError as e:
# Only the first error is reported
print(len(e.errors()))
# > 1

Validating JSON-Encoded Strings

The Json type allows you to validate strings that contain JSON-encoded data. Pydantic will parse the string and then validate the resulting object against the parametrized type.

from pydantic import BaseModel, Json

class WebhookPayload(BaseModel):
# Expects a JSON string that parses into a list of strings
event_ids: Json[list[str]]

# Input is a string, but the field becomes a list[str]
payload = WebhookPayload(event_ids='["evt_1", "evt_2"]')
print(payload.event_ids)
# > ['evt_1', 'evt_2']

Troubleshooting

  • RootModel and Extra Fields: RootModel does not support model_config['extra']. If you need to handle extra data, use a standard BaseModel.
  • Static Analysis: If your IDE does not recognize the types returned by conlist or conset, switch to the Annotated[list[T], Field(...)] syntax.
  • ImportString Defaults: If you use ImportString with a string default, you must set validate_default=True in the Field definition for the string to be evaluated and imported automatically.