SQLAlchemy и ORM

Раздел про SQLAlchemy 2.x: Core и ORM, модели через Mapped, связи, сессия и unit of work, ленивая загрузка и N+1, запросы, транзакции и блокировки, async, Alembic, производительность и грабли.

Зачем для UCP. Репозиторий и Unit of Work в Python-сервисе почти всегда стоят на SQLAlchemy, и большинство странностей «обработчик работает, а данные не те» объясняются тем, как ORM ведёт себя между flush, commit и ленивой загрузкой. Без этой фазы обработчики команд пишут вслепую.

Одиннадцать статей, по одной теме на статью, читать лучше подряд.

Модель

  1. Что такое ORM и SQLAlchemy — Core и ORM, стиль 2.0, движок и пул, когда ORM помогает, а когда мешает.
  2. Модели и маппинг — DeclarativeBase, Mapped, типы колонок, умолчания, ограничения и соглашения об именах.
  3. Связи между таблицами — relationship, back_populates, многие-ко-многим, каскады и удаление.

Сессия и загрузка

  1. Сессия и unit of work — состояния объекта, identity map, flush против commit, expire_on_commit.
  2. Ленивая загрузка и N+1 — стратегии загрузки, как увидеть N+1 в логах и как его убрать.
  3. Запросы — select() в стиле 2.0, соединения, агрегаты, подзапросы, text() и постраничная выборка.

Эксплуатация

  1. Транзакции и блокировки — границы транзакции, savepoint, уровни изоляции, FOR UPDATE, оптимистичная версия.
  2. Асинхронный SQLAlchemy — AsyncSession, драйверы, greenlet, что нельзя делать в async и как это обойти.
  3. Миграции: Alembic — автогенерация и её пределы, расширение и сжатие, запуск в выкате.
  4. Производительность — пул, пакетные вставки, потоковое чтение, отложенные колонки, как измерять.
  5. Типичные грабли — DetachedInstanceError, сессия между задачами, autoflush, JSON без отслеживания, наивное время.