Валидация данных в Python: что нужно знать заранее
Первое, что ломается в проекте на входе данных — это ручные проверки через if. Разбираем, как за полчаса собрать надёжную валидацию на Pydantic и когда хватит dataclasses.

К концу этого гайда у вас будет рабочая модель, которая принимает словарь (например, JSON от запроса), проверяет типы и ограничения, а при ошибке говорит понятным языком, что именно не так и в каком поле. На всё уйдёт примерно 30–40 минут вместе с установкой. Мы будем использовать Pydantic 2.x — самую распространённую библиотеку для этой задачи в 2024 году.
Валидация данных — это проверка, что пришедшие извне данные соответствуют тому, что ваш код ожидает: строка не пустая, возраст — число от 0 до 150, email похож на email. Без неё в базу попадает мусор, а функции падают с непонятными ошибками где-то глубоко внутри.
Что нужно иметь до начала
- Python 3.8 или новее. Pydantic 2.x требует минимум 3.8. Проверить:
python --versionв терминале. - Установленный pip. Обычно идёт вместе с Python.
- Виртуальное окружение — не обязательно, но желательно, чтобы не засорять систему. Создаётся командой
python -m venv venv.
Установите Pydantic:
pip install pydanticПроверка, что всё встало: выполните python -c "import pydantic; print(pydantic.version.VERSION)". Должна вывестись версия вида 2.x.x. Если видите 1.x — вы ставите в окружение, где уже был старый Pydantic; синтаксис ниже частично не совпадёт.
Шаг 1. Опишите модель
Модель — это класс, где каждое поле объявлено с типом. Pydantic сам превратит это в проверку.
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
email: str
# Создаём объект из словаря
data = {"name": "Иван", "age": 30, "email": "ivan@example.com"}
user = User(**data)
print(user.name) # Иван
print(user.age) # 30Как понять, что получилось: строка print(user.name) выведет Иван. Если запустили без ошибок — модель работает.
Шаг 2. Посмотрите, как отлавливается брак
Передайте заведомо неверные данные и поймайте исключение.
from pydantic import BaseModel, ValidationError
class User(BaseModel):
name: str
age: int
email: str
bad_data = {"name": "Иван", "age": "тридцать", "email": "ivan@example.com"}
try:
user = User(**bad_data)
except ValidationError as error:
print(error)В консоль выведется сообщение, где будет указано поле age и причина: значение не приводится к целому числу. Именно это отличает библиотеку от ручных if — вы сразу видите, какое поле виновато.
Ручная проверка через цепочку if растёт быстрее, чем данные. Через полгода это простыня из проверок, в которой никто не помнит, покрыт ли case с пустой строкой. Модель держит всё правило в одном месте — рядом с самим полем.
Шаг 3. Добавьте ограничения на значения
Тип — это только начало. Возраст должен быть неотрицательным, имя — непустым. Для этого есть Field.
from pydantic import BaseModel, Field, EmailStr
class User(BaseModel):
name: str = Field(min_length=1, max_length=100)
age: int = Field(ge=0, le=150) # ge = больше-или-равно, le = меньше-или-равно
email: EmailStr # проверка формата emailТип EmailStr требует дополнительной установки: pip install "pydantic[email]". Если поставить забыли — при импорте получите ошибку про отсутствующий пакет email-validator.
Как понять, что ограничения работают: передайте age=200 и поймайте ValidationError — в тексте будет упомянуто, что значение должно быть меньше или равно 150.
Шаг 4. Необязательные поля и значения по умолчанию
Не все данные приходят всегда. Поле можно сделать необязательным.
from typing import Optional
from pydantic import BaseModel, Field
class User(BaseModel):
name: str
age: int = Field(ge=0, le=150)
phone: Optional[str] = None # может отсутствовать
is_active: bool = True # значение по умолчанию
user = User(name="Иван", age=30)
print(user.phone) # None
print(user.is_active) # TrueЕсли поле объявлено без значения по умолчанию — оно обязательное, и его отсутствие даст ошибку валидации.
Шаг 5. Получите чистый словарь обратно
После проверки данные обычно нужно сохранить или отдать дальше. В Pydantic 2.x метод называется model_dump (в первой версии был dict — если найдёте старый пример с .dict(), это оно).
user = User(name="Иван", age=30)
print(user.model_dump())
# {'name': 'Иван', 'age': 30, 'phone': None, 'is_active': True}
print(user.model_dump_json())
# JSON-строка с теми же даннымиЕсли не получилось
ModuleNotFoundError: No module named 'pydantic'— библиотека не установлена в текущее окружение. Проверьте, что активировали то же venv, в котором ставили пакет.ImportError: email-validator is not installed— используетеEmailStrбез нужного пакета. Выполнитеpip install "pydantic[email]".AttributeError: 'User' object has no attribute 'dict'— вы на Pydantic 2.x, а вызываете метод из первой версии. Замените.dict()на.model_dump().- Данные проходят проверку, хотя не должны — по умолчанию Pydantic мягко приводит типы: строка
"30"станет числом 30. Если нужна строгая проверка без приведения, изучите strict-режим в документации. ValidationErrorс непонятным полем — читайте текст ошибки целиком: там указан путь до поля (например,address.cityдля вложенной модели) и причина.
Когда Pydantic избыточен
Если данные не приходят извне, а рождаются внутри вашего же кода и вы им доверяете, полноценная валидация не нужна. Для простой группировки полей без проверок хватит встроенных dataclasses — они легче и не требуют зависимости. Pydantic оправдан там, где на входе непредсказуемые данные: тело HTTP-запроса, содержимое конфига, ответ внешнего API, строки из CSV.
Что делать дальше
Следующий разумный шаг — вложенные модели: одно поле может быть другой моделью (адрес внутри пользователя), и Pydantic проверит всю структуру рекурсивно. Дальше — валидаторы полей (field_validator) для правил, которые не выражаются через Field: например, что дата окончания позже даты начала. Если пишете веб-API, посмотрите FastAPI — он строит валидацию запросов на тех же моделях Pydantic, и описанное здесь переносится без изменений.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Pydantic — официальная документация, Pydantic: Fields (Field constraints)
Частые вопросы
У меня установлен Pydantic 1.x, примеры не работают. Что делать?
Чем Pydantic отличается от dataclasses?
Почему строка "30" превратилась в число 30, я этого не просил?
Что будет, если обязательное поле не пришло?
Валидация замедляет код на больших объёмах данных?
Можно ли проверять вложенные структуры, например список объектов?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.