📖 Теория: Pydantic — валидация и сериализация данных
⚡ Краткий конспект
- Pydantic — библиотека для валидации данных через аннотации типов Python.
BaseModel— базовый класс. Поля аннотируются типами, Pydantic проверяет их автоматически.model_validate_json()— из JSON-строки в объект.model_dump_json()— из объекта в JSON-строку.Field()— добавляет ограничения:gt=0(больше 0),min_length=2,default=True,alias="available".@field_validator— кастомная валидация поля (Pydantic v2).Configвнутри модели — глобальные настройки: обрезка пробелов, минимальная длина строк, кастомные JSON-энкодеры.
Что такое Pydantic
Pydantic — это библиотека для Python, которая использует аннотации типов для валидации данных. Она проверяет, что входящие данные соответствуют ожидаемым типам, автоматически приводит их к нужному формату и сообщает об ошибках.
Где используется:
- API — валидация входящих JSON-данных в Flask и FastAPI
- Конфигурации — проверка настроек приложения
- Базы данных — совместимость с SQLAlchemy
- Сериализация — преобразование объектов в JSON и обратно
Установка
pip install pydantic
Для работы с EmailStr:
pip install pydantic[email]
BaseModel — основа моделей
Все модели Pydantic наследуются от BaseModel. Поля класса аннотируются типами:
from pydantic import BaseModel
class User(BaseModel):
id: int
name: str
age: int
is_active: bool = True
Что происходит:
- При создании объекта
User(id=1, name="Anna", age=25)Pydantic проверяет типы. - Если передать
age="not_a_number"— будет ошибкаValidationError. - Поле
is_activeимеет значение по умолчаниюTrue, его можно не передавать.
Вложенные модели
Модель может содержать другую модель как поле:
from pydantic import BaseModel
class Address(BaseModel):
city: str
street: str
house_number: int
class User(BaseModel):
id: int
name: str
age: int
address: Address
Pydantic рекурсивно валидирует вложенную структуру. Если address не соответствует модели Address — ошибка.
JSON и Pydantic
JSON (JavaScript Object Notation) — универсальный формат обмена данными. Pydantic умеет преобразовывать модели в JSON и обратно.
Десериализация: JSON → модель
from pydantic import BaseModel, ValidationError
class User(BaseModel):
name: str
age: int
json_string = '{"name": "John", "age": 30}'
try:
user = User.model_validate_json(json_string, strict=True)
print(user) # name='John' age=30
except ValidationError as e:
print("Validation error:", e)
strict=True — строгий режим: Pydantic не будет пытаться привести типы (например, строку "30" к числу 30).
Сериализация: модель → JSON
user = User(name="John", age=30)
json_output = user.model_dump_json()
print(json_output) # {"name":"John","age":30}
Наследование моделей
Модели Pydantic поддерживают наследование, как обычные Python-классы:
from pydantic import BaseModel, EmailStr
class User(BaseModel):
name: str
email: EmailStr
class AdminUser(User):
is_superuser: bool
access_level: int
AdminUser содержит все поля User + свои собственные.
Методы в моделях
В модель можно добавлять методы:
class User(BaseModel):
name: str
age: int
def greet(self) -> str:
return f"Hello, my name is {self.name} and I am {self.age} years old."
def __str__(self) -> str:
return f"{self.name}, {self.age} years old"
Field — валидация и метаданные
Field() позволяет задать ограничения и метаданные для поля:
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str
description: str = Field(None, description="Описание продукта")
price: float = Field(gt=0, description="Цена должна быть больше нуля")
in_stock: bool = Field(default=True, alias="available")
| Параметр | Значение | Пример |
|---|---|---|
default | Значение по умолчанию | default=True |
gt | Больше чем (greater than) | gt=0 |
ge | Больше или равно | ge=18 |
le | Меньше или равно | le=99 |
min_length | Минимальная длина строки | min_length=2 |
max_length | Максимальная длина строки | max_length=50 |
alias | Альтернативное имя в JSON | alias="available" |
description | Описание поля | description="Цена" |
... (Ellipsis) означает, что поле обязательное. Например: name: str = Field(..., min_length=3).
Специальные типы Pydantic
Pydantic предоставляет готовые типы для частых сценариев:
| Тип | Описание | Требует |
|---|---|---|
EmailStr | Валидный email-адрес | pip install pydantic[email] |
HttpUrl | Валидный URL (http/https) | — |
List[str] | Список строк | from typing import List |
PositiveInt | Положительное целое число | from pydantic import PositiveInt |
Кастомная валидация: @field_validator
Для сложных проверок используй декоратор @field_validator (Pydantic v2):
from pydantic import BaseModel, field_validator, EmailStr
class User(BaseModel):
name: str
age: int
email: EmailStr
@field_validator('email')
def check_email_domain(cls, value: str) -> str:
allowed = ['example.com', 'test.com']
domain = value.split('@')[-1]
if domain not in allowed:
raise ValueError(f"Email должен быть из доменов: {', '.join(allowed)}")
return value
@field_validator. В v1 использовался @validator — не путай!
Валидация, зависящая от нескольких полей
Используй model_validator (Pydantic v2) для проверок, где нужно сравнить несколько полей:
from pydantic import BaseModel, model_validator
class User(BaseModel):
age: int
is_employed: bool
@model_validator(mode='after')
def check_employment_age(self):
if self.is_employed and not (18 <= self.age <= 65):
raise ValueError("Если занят, возраст должен быть от 18 до 65")
return self
Настройки модели: model_config (ConfigDict)
В Pydantic v2 глобальные настройки модели задаются атрибутом model_config = ConfigDict(...):
from pydantic import BaseModel, ConfigDict
class User(BaseModel):
model_config = ConfigDict(
str_strip_whitespace=True, # Обрезать пробелы по краям
str_min_length=1, # Минимальная длина строки
validate_assignment=True, # Валидировать при присваивании
)
name: str
age: int
Для кастомной сериализации даты в JSON используется декоратор @field_serializer (в v2 он заменил устаревший json_encoders):
from datetime import datetime
from pydantic import BaseModel, field_serializer
class User(BaseModel):
signup_ts: datetime
@field_serializer("signup_ts")
def serialize_ts(self, v: datetime) -> str:
return v.strftime("%d-%m-%Y %H:%M")
user = User(signup_ts=datetime.now())
print(user.model_dump_json()) # {"signup_ts":"08-06-2026 22:16"}
class Config: и словарь json_encoders. Сравнение v1 → v2 — на странице ⚖️ Старый vs Новый.