1. Pydantic v2: ключевые концепции
Pydantic — библиотека для валидации данных на Python с помощью аннотаций типов. Подробнее — Урок 03.
BaseModel и объявление полей
Каждое поле модели объявляется как аннотация типа. Pydantic автоматически проверяет типы при создании объекта.
from pydantic import BaseModel, EmailStr, Field
from typing import Annotated
from decimal import Decimal
class UserProfile(BaseModel):
username: str
password: str = Field(min_length=8, description="Min 8 characters")
email: EmailStr
@field_validator (Pydantic v2)
Кастомный валидатор в Pydantic v2 объявляется через @field_validator с обязательным @classmethod:
from pydantic import BaseModel, field_validator
from datetime import datetime
class Event(BaseModel):
title: str
date: datetime
@field_validator('date')
@classmethod
def date_must_be_future(cls, v: datetime) -> datetime:
if v < datetime.now():
raise ValueError("Event date must be in the future")
return v
@field_validator требует @classmethod. В лекции можно встретить старый @validator без @classmethod — это Pydantic v1. Подробнее — Старый vs Новый.
Field-ограничения и Annotated
Для числовых типов и строк с ограничениями в Pydantic v2 используется Annotated совместно с Field:
from typing import Annotated
from decimal import Decimal
from pydantic import BaseModel, Field
class Transaction(BaseModel):
# Decimal > 0
amount: Annotated[Decimal, Field(gt=0)]
# Строка с паттерном
transaction_type: Annotated[str, Field(pattern=r"^(debit|credit)$")]
# Строка ровно 3 символа
currency: Annotated[str, Field(min_length=3, max_length=3)]
ConfigDict и json_schema_extra
Конфигурация модели в Pydantic v2 задаётся через model_config = ConfigDict(...) (вместо class Config из v1):
from pydantic import BaseModel, Field, ConfigDict
class UserProfile(BaseModel):
username: str
password: str = Field(min_length=8)
model_config = ConfigDict(
str_strip_whitespace=True,
json_schema_extra={
"example": {
"username": "john_doe",
"password": "securePass123"
}
}
)
2. SQLAlchemy 2.x: ключевые концепции
SQLAlchemy — ORM-библиотека для Python. Подробнее — Урок 05.
create_engine
Движок (engine) — точка входа SQLAlchemy. Строка подключения зависит от СУБД:
from sqlalchemy import create_engine
# MySQL через pymysql
engine = create_engine('mysql+pymysql://user:password@localhost/mydb')
# SQLite в памяти (для тестов)
engine = create_engine('sqlite:///:memory:', echo=True)
DeclarativeBase и Mapped/mapped_column
В SQLAlchemy 2.x базовый класс создаётся наследованием от DeclarativeBase, поля объявляются через Mapped с аннотациями типов:
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import String, Integer
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = 'users'
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(50))
age: Mapped[int] = mapped_column(Integer)
ForeignKey и relationship
Связи между таблицами задаются через ForeignKey и relationship:
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Post(Base):
__tablename__ = 'posts'
id: Mapped[int] = mapped_column(primary_key=True)
title: Mapped[str] = mapped_column(String(255))
user_id: Mapped[int] = mapped_column(ForeignKey('users.id'))
user: Mapped["User"] = relationship("User", back_populates="posts")
Работа с Session
В SQLAlchemy 2.x сессия используется через контекстный менеджер — закрытие автоматическое:
from sqlalchemy.orm import Session
Base.metadata.create_all(engine)
with Session(engine) as session:
new_user = User(name="Alice", age=30)
session.add(new_user)
session.commit()
# Запрос
users = session.query(User).filter_by(name="Alice").all()
# Удаление
session.delete(new_user)
session.commit()