Представьте: API на FastAPI отдаёт данные из PostgreSQL, всё работает на ноутбуке, тесты зелёные. В пятницу выкатываете на сервер — и через двадцать минут под нагрузкой в 40 одновременных запросов сервис начинает отдавать 502. В логах — исчерпан пул соединений с базой. Код тот же, что и локально. Разница только в том, что локально вы были единственным клиентом.
Именно в этот момент заканчивается «изучение фреймворка» и начинается веб-разработка. Django и FastAPI — не два конкурирующих инструмента, между которыми надо выбрать «правильный», а два разных ответа на разные вопросы. Django отвечает на вопрос «как собрать большое приложение с админкой, авторизацией и ORM, не изобретая велосипед». FastAPI — «как отдать максимальную пропускную способность на I/O-bound нагрузке с внятными типами и схемами».
Ниже — разбор того, как эта пара работает на практике, где ломается механизм, и какие пути освоения реально существуют. Курс Django и FastAPI — Python Web здесь — один из способов, не единственный; о trade-offs честно.
Почему стоит разбираться именно в этой связке
Механизм прост: Python-бэкенд в большинстве продуктов — это слой, который принимает HTTP, валидирует вход, ходит в базу и во внешние сервисы, и возвращает JSON. Всё остальное — детали. Django и FastAPI покрывают этот слой почти полностью, но с противоположных концов спектра.
Django — это «батарейки в комплекте». ORM, миграции, админка, аутентификация, формы, CSRF-защита, а через Django REST Framework — сериализаторы, ViewSet'ы, роутеры, права доступа. Вы платите за это монолитностью: фреймворк диктует структуру, а синхронный цикл запроса упирается в воркеры.
FastAPI — это «собери сам, но быстро». Pydantic-схемы дают валидацию и документацию из одних и тех же типов, async даёт конкурентность на I/O, dependency injection даёт аккуратную сборку зависимостей. Вы платите за это тем, что ORM, миграции и админку придётся подключать отдельно — обычно SQLAlchemy плюс Alembic, и следить за их согласованностью.
Почему это стоит осваивать именно вместе: на реальной работе вы почти гарантированно встретите оба. Классический сценарий — унаследованный Django-монолит с админкой и внутренними отчётами, к которому пристраивают отдельный async-сервис на FastAPI для публичного API или WebSocket-уведомлений. Умение держать в голове обе модели и понимать, где проходит граница, — это и есть профессиональный уровень.
Разбор по существу: как практик строит эндпоинт и что идёт не так
Возьмём конкретную задачу. Есть сервис заказов, нужно отдать список заказов пользователя с пагинацией, с фильтром по статусу, и чтобы это держало нагрузку. Разберём порядок действий на FastAPI — и типичные провалы.
Шаг 1. Схемы Pydantic. Сначала описываем вход и выход типами: OrderOut с полями id, status, created_at, total; OrderQuery с limit, offset, status. Валидация и OpenAPI-документация появляются автоматически. Типичная ошибка новичка — отдавать ORM-объект напрямую и «дорисовывать» поля в роутере. Через месяц схема расходится с реальностью, потому что её никто не держит в одном месте.
Шаг 2. Зависимость сессии. Через Depends заводим сессию SQLAlchemy с корректным закрытием. Здесь же — первая ловушка: если сессия создаётся на уровне модуля, а не на запрос, вы получите гонки и утечки соединений. Правильно — фабрика сессий и yield-зависимость, которая закрывает сессию в finally.
Шаг 3. Запрос с пагинацией. select(Order).where(Order.user_id == uid).order_by(Order.created_at.desc()).limit(limit).offset(offset). На 10 000 заказов это работает. На миллионе — offset 900 000 заставляет базу прочитать и отбросить 900 000 строк. Практик это знает и переходит на keyset-пагинацию по (created_at, id). Это не «оптимизация потом», это решение, которое дешево принять сразу и дорого менять после того, как клиенты встроили offset-пагинацию в свои интеграции.
Шаг 4. N+1. Если к каждому заказу подтягиваются позиции, наивный код сделает один запрос за списком и по запросу на каждый заказ. При limit=50 это 51 запрос вместо двух. Заметить это на локальной базе с 20 записями невозможно — там всё мгновенно. Ловится через selectinload/joinedload и через лог SQL.
Шаг 5. Пул соединений. Дефолтный размер пула (обычно 5 соединений плюс overflow) рассчитан на скромную нагрузку. При 8 воркерах uvicorn и пуле в 5 соединений на воркер вы упираетесь в лимит PostgreSQL max_connections. Нагрузочный тест на 100 одновременных запросов покажет очередь и таймауты. Решение — либо осознанно ограничить число воркеров, либо поставить PgBouncer, либо честно посчитать: 8 воркеров × (5 + 10 overflow) = до 120 соединений, а дефолтный max_connections в PostgreSQL — 100.
Вот этот последний пункт — неочевидный вывод, до которого редко доходят за пять минут поиска. Люди годами считают, что «FastAPI быстрый, значит масштабируется», и не связывают 502 под нагрузкой с арифметикой пула соединений.
Где ломается сам механизм
Это не ошибки читателя — это отказы схемы. Django и FastAPI спроектированы под определённые условия, и когда условия меняются, ломается не ваш код, а допущения фреймворка.
Сценарий 1: синхронный код внутри async-эндпоинта
FastAPI даёт async, но если внутри async-функции вызвать синхронный драйвер базы или requests, вы заблокируете event loop. Один такой вызов — и весь воркер перестаёт принимать запросы, пока идёт блокирующая операция. Как заметить заранее: под нагрузкой время ответа растёт нелинейно, хотя CPU и память свободны. Что делать, если уже поздно: обернуть блокирующий вызов в run_in_threadpool, перейти на async-драйвер (asyncpg), либо честно объявить эндпоинт синхронным (def вместо async def) — FastAPI сам выполнит его в пуле потоков.
Сценарий 2: миграции разъехались с моделями
В FastAPI+SQLAlchemy модели и Alembic живут отдельно. Кто-то поправил модель, забыл сгенерировать миграцию, и на проде колонки нет. Django здесь защищённее: makemigrations и migrate встроены, а manage.py makemigrations --check в CI ловит расхождение. Как заметить заранее: добавить в CI проверку, что после makemigrations нет новых файлов. Если поздно: откат миграции на живой базе — отдельная операция, и её надо уметь делать до инцидента, а не во время.
Сценарий 3: сериализатор DRF стал узким местом
Django REST Framework удобен, но сериализаторы с вложенными связями и SerializerMethodField могут превратить один эндпоинт в сотни запросов. Схема не ломается — она просто перестаёт масштабироваться. Как заметить: снова лог SQL и замер времени ответа на реалистичном объёме данных. Что делать: select_related/prefetch_related, а на тяжёлых read-эндпоинтах — отказаться от «универсального» сериализатора в пользу явного values()-запроса.
Сценарий 4: async-код встретил sync-библиотеку
Половина экосистемы Python всё ещё синхронна. Асинхронный сервис на FastAPI, которому нужна библиотека без async-поддержки, вынужден держать пул потоков или отдельный процесс. Это не ошибка — это структурное ограничение, и его надо знать до того, как выберете FastAPI «потому что модно».
| Критерий | Django + DRF | FastAPI |
|---|---|---|
| Старт проекта | Быстрый, много готового | Быстрее код, но больше сборки |
| Админка | Встроенная | Нужна отдельная |
| ORM и миграции | В комплекте | SQLAlchemy + Alembic отдельно |
| Конкурентность | Воркеры/процессы | async на I/O |
| Типизация и схемы | Через DRF-сериализаторы | Pydantic из коробки |
| Типичный провал | N+1 в сериализаторах | Блокировка event loop |
Пути освоения и честные trade-offs
Есть три реалистичных маршрута, и они отличаются не только временем и деньгами, но и тем, какие навыки вы получите.
Самостоятельно по документации. Официальные docs Django и FastAPI — одни из лучших в экосистеме. Плюс: бесплатно, вы учитесь читать первоисточник, а это навык на всю карьеру. Минус: документация показывает, как сделать правильно, но не показывает, что пойдёт не так. N+1, пул соединений, блокировка event loop — этого в туториалах нет, потому что туториалы пишут для работающего примера, а не для продакшена. Обратной связи нет: вы не узнаете, что ваше решение кривое, пока оно не упадёт.
Практика на своих проектах. Самый честный путь по результату, но самый дорогой по времени. Вы столкнётесь с реальными отказами — но, возможно, через полгода и после нескольких инцидентов. Плюс: навык остаётся навсегда. Минус: ошибки в проде стоят дорого, а некоторые (например, неверная схема миграций) — дорого и необратимо.
Структурированный курс. Здесь ценность не в «уроках», а в том, что кто-то уже собрал грабли в одном месте и разобрал их на примерах. В курсе Django и FastAPI — Python Web разбирают именно эту связку — DRF, ORM, админку с одной стороны, async, Pydantic, WebSocket и SQLAlchemy с Alembic с другой, плюс JWT/OAuth2, pytest и деплой через Docker и CI/CD. Материал текстовый, уроки персонализируются под уровень студента, а развёрнутые ответы можно разобрать в AI-чате курса — то есть обратная связь по вашим решениям есть, но не в формате «автопроверки на всё».
Если вы уже пишете на Python и хотите сравнить подходы к бэкенду в целом, полезно посмотреть на бэкенд-разработку на Node.js — там те же вопросы конкурентности и пула соединений стоят иначе, и контраст помогает понять, что именно вы выбираете. А про типизацию как отдельный навык — TypeScript — статическая типизация для JavaScript: полный курс TypeScript, от базовых типов до дженериков и реального продакшн-кода: Pydantic и типы в FastAPI решают ту же задачу «сделать контракт явным».
Кому этот путь подходит, а кому нет
Подходит, если вы уже уверенно пишете на Python, знаете SQL на уровне JOIN и индексов, и вам нужно перейти от скриптов к сервисам. Обе модели — Django и FastAPI — дадут вам язык, на котором обсуждают бэкенд на собеседованиях и в командах. Если вы хотите понимать, почему сервис падает под нагрузкой, а не просто «сделать CRUD», — это ваша тема.
Не подходит, если вы ещё не писали на Python вне учебных задач: async, dependency injection и ORM без базы превратятся в копирование кода. Также не стоит идти сюда, если вам нужен только фронтенд или только аналитика данных — глубина по бэкенду будет избыточной.
Веб-разработка на Python — область, где «знаю фреймворк» и «умею строить сервис» расходятся довольно быстро, и расходятся именно на отказах механизма: пулах соединений, миграциях, блокировке event loop, N+1. Курс Django и FastAPI — Python Web разбирает эти сценарии на примерах и даёт обратную связь по вашим решениям — подробности и запись на странице курса.