Pydantic — одна из ключевых библиотек в современном Python-стеке для работы с данными. Она обеспечивает валидацию, парсинг и сериализацию с использованием аннотаций типов. Вот как извлечь из неё максимум пользы.
1. Валидация с кастомными правилами
Используйте @validator для сложной логики:
from pydantic import BaseModel, validator
class User(BaseModel):
....username: str
....password: str
....@validator("password")
....def validate_password(cls, v):
........if len(v) < 8:
............raise ValueError("Пароль слишком короткий")
........if not any(char.isdigit() for char in v):
............raise ValueError("Пароль должен содержать цифру")
....return v
user = User(username="john", password="secure123") # Корректно
2. Динамические значения по умолчанию
Используйте default_factory для генерации значений:
from uuid import uuid4
from pydantic import BaseModel, Field
class Document(BaseModel):
....id: str = Field(default_factory=lambda: uuid4().hex)
....content: str
doc = Document(content="Hello")
print(doc.id) # Например: "e4eaaaf2d3a74d3b8b0e7b8d7"
3. Модели для ошибок и ответов API
Создайте унифицированные модели для API:
class ErrorResponse(BaseModel):
....error: str
....details: dict = {}
class SuccessResponse(BaseModel):
....data: dict
....message: str = "Success"
# Использование в FastAPI:
from fastapi import status, HTTPException
def handle_error(error: str, status_code: status):
....raise HTTPException(
........status_code=status_code,
........detail=ErrorResponse(error=error).dict()
....)
4. Работа с наследованием моделей
Комбинируйте модели через наследование:
class TimestampMixin(BaseModel):
....created_at: datetime = Field(default_factory=datetime.now)
....updated_at: datetime = Field(default_factory=datetime.now)
class Post(TimestampMixin):
....title: str
....content: str
post = Post(title="Hello", content="World")
print(post.created_at) # 2025-05-15 12:00:00
5. Парсинг данных из неизвестных источников
Используйте parse_obj для сырых данных:
raw_data = '{"name": "Alice", "age": "30"}' # Возможно из внешнего API
data = User.parse_raw(raw_data)
print(data) # name='Alice' age=30
6. Валидация данных с условиями
@root_validator для проверки всей модели:
class Order(BaseModel):
....items: list[str]
....discount_code: str = None
....@root_validator
....def validate_discount(cls, values):
........items, code = values.get("items"), values.get("discount_code")
........if code and len(items) < 3:
............raise ValueError("Скидка только для 3+ товаров")
....return values
7. Интеграция с ORM (SQLAlchemy, Django)
Используйте from_orm для преобразования:
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class UserDB(Base):
....__tablename__ = "users"
....id = Column(Integer, primary_key=True)
....name = Column(String)
class UserPydantic(BaseModel):
....id: int
....name: str
....class Config:
........orm_mode = True
db_user = UserDB(name="John")
pydantic_user = UserPydantic.from_orm(db_user)
8. Работа с конфигурацией
Удобное управление настройками через BaseSettings:
from pydantic import BaseSettings, PostgresDsn
class AppSettings(BaseSettings):
....db_url: PostgresDsn
....debug: bool = False
....class Config:
........env_file = ".env"
........env_prefix = "APP_"
settings = AppSettings() # Автоматически загружает APP_DB_URL из .env
9. Кастомные типы данных
Создавайте свои типы для специфичных данных:
from pydantic import BaseModel
class RGBColor(BaseModel):
....r: int = Field(0, ge=0, le=255)
....g: int = Field(0, ge=0, le=255)
....b: int = Field(0, ge=0, le=255)
class Design(BaseModel):
....background: RGBColor = RGBColor(r=255, g=255, b=255)
10. Эволюция моделей с Field
Плавное изменение схемы:
class Product(BaseModel):
....id: int
....name: str
....# Старое поле, будет удалено в будущем
....old_field: str = Field(
........default=None,
........deprecated=True,
........description="Используйте `new_field` вместо этого"
....)
11. Валидация путей и файлов
FilePath и DirectoryPath для работы с ФС:
from pydantic import FilePath, DirectoryPath
class Config(BaseModel):
....config_path: FilePath
....log_dir: DirectoryPath
cfg = Config(config_path="/app/config.yaml", log_dir="/logs")
12. Модели для тестирования
Используйте Pydantic в тестах:
def test_user_creation():
....data = {"username": "test", "password": "secret123"}
....user = User(**data)
....assert user.username == "test"
....with pytest.raises(ValueError):
........User(username="test", password="short") # Невалидный пароль
13. Расширение через плагины
Интеграция с другими инструментами:
- pydantic-settings: Для расширенных конфигураций.
- pydantic-extra-types: Дополнительные типы данных (IBAN, MAC-адреса).
- pydantic-django: Интеграция с Django ORM.
14. Оптимизация производительности
- Pydantic V2: Написана на Rust (до 50x быстрее V1).
- Используйте model_construct() для создания объектов без валидации, когда уверены в данных:
user = User.model_construct(username="admin", password="x"*8) # Без валидации
15. Генерация схем для документации
Автоматическая генерация OpenAPI-схем в FastAPI:
from fastapi import FastAPI
app = FastAPI()
@app.post("/users/", response_model=User)
def create_user(user: User):
....return user
Схема эндпоинта будет доступна в /docs.
Заключение
Pydantic — это не просто валидатор данных, а мощный инструмент для построения надёжных и поддерживаемых приложений. Его ключевые преимущества:
- Типизация: Статический анализ с mypy.
- Безопасность: Защита от инъекций через кастомные типы.
- Интеграция: Работа с ORM, веб-фреймворками, конфигами.
- Производительность: Оптимизированные алгоритмы в V2.
Пример полной системы:
# Модель -> Настройки -> API
class DatabaseConfig(BaseSettings):
....url: PostgresDsn
class AppConfig(BaseSettings):
....db: DatabaseConfig
....debug: bool
....config = AppConfig()
class User(BaseModel):
....id: UUID
....name: str
# FastAPI эндпоинт
@app.post("/users", response_model=User)
def create_user(user: User):
....db_user = UserDB(**user.dict())
....session.add(db_user)
....session.commit()
....return User.from_orm(db_user)
Совет: Всегда обновляйтесь до последней версии Pydantic для использования современных возможностей и оптимизаций. Библитория активно развивается и становится стандартом де-факто для работы с данными в Python.
Подписывайтесь:
Телеграм https://t.me/lets_go_code
Канал "Просто о программировании" https://dzen.ru/lets_go_code