Перейти к основному содержимому

FastAPI и база данных

Разработчику Архитектору

См. также: FastAPI · Первая программа на FastAPI · Базы данных в Python · Создание API


FastAPI - маршрут от URL до ответа

В обзоре FastAPI и первой программе заметки хранились в словаре _notes в памяти: перезапустили Uvicorn — список пуст. В реальных проектах данные лежат в базе данных (БД): таблицы на диске, переживают перезапуск сервера.

Здесь — сквозной сценарий: HTTP-запрос → FastAPI → SQLAlchemy → SQLite (или PostgreSQL) → JSON-ответ.

Общие термины (DB-API, драйвер, транзакция, пул) — в главе про базы данных.


Словарь

ТерминПростыми словами
ORMObject-Relational Mapping: класс Python ↔ таблица в БД
Сессия (Session)"Рабочая копия" данных на время запроса: читаете, меняете, commit
МиграцияВерсионированное изменение схемы (добавили столбец — файл в git)
commitЗафиксировать изменения в БД
rollbackОтменить незакоммиченные изменения при ошибке
CRUDCreate, Read, Update, Delete
DTOОбъект для JSON (часто Pydantic-модель)

Стек по слоям

СлойБиблиотекаРоль
HTTP, маршрутыFastAPIURL, коды ответа, Depends
Валидация JSONPydanticПроверка тела запроса до SQL
Таблицы и SQLSQLAlchemy 2Классы UserRow, запросы
Файл/сервер БДSQLite / PostgreSQLХранение
ЗапускUvicornASGI-сервер
pip install fastapi uvicorn sqlalchemy pydantic

Разбор фрагмента:

  • Устанавливаются компоненты HTTP-слоя, ORM и валидации схем.
  • Такой набор достаточен для первого CRUD-сервиса с БД на FastAPI.

SQLite — файл app.db рядом с проектом. В продакшене — PostgreSQL и пул соединений (см. Работа с базами данных в Python).


Две модели — таблица и JSON

Таблица (SQLAlchemy)

Код ITЗагрузка примера кода…

ЭлементСмысл
__tablename__Имя таблицы в SQL
primary_key=TrueУникальный id строки
unique=TrueДва одинаковых username нельзя
server_default=func.now()Время создания ставит СУБД

Схемы API (Pydantic)

from pydantic import BaseModel, Field

class UserCreate(BaseModel):
username: str
email: str = Field(..., pattern=r"^[^@]+@[^@]+\.[^@]+$")

class UserRead(BaseModel):
id: int
username: str
email: str

model_config = {"from_attributes": True}

from_attributes=True — ответ из ORM: UserRead.model_validate(row).


Подключение и get_db

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session

DATABASE_URL = "sqlite:///./app.db"
engine = create_engine(
DATABASE_URL,
connect_args={"check_same_thread": False},
)
SessionLocal = sessionmaker(bind=engine, autoflush=False, autocommit=False)

def init_db():
Base.metadata.create_all(bind=engine)

Разбор фрагмента:

  • create_engine(...) создаёт подключение к СУБД по DATABASE_URL.
  • sessionmaker(...) настраивает фабрику сессий для unit-of-work.
  • Base.metadata.create_all(...) создаёт таблицы из ORM-моделей, если их ещё нет.
from fastapi import Depends

def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

Разбор фрагмента:

  • Функция выдаёт отдельную сессию БД на каждый HTTP-запрос.
  • yield передаёт объект в обработчик, а finally гарантирует закрытие.
  • Такой шаблон предотвращает утечки соединений.

check_same_thread=False — особенность SQLite с FastAPI. Одна сессия на HTTP-запрос, закрытие в finally.


CRUD с разбором шагов

Код ITЗагрузка примера кода…

ШагДействие
body: UserCreatePydantic проверил JSON
db.add(row)Пометить строку для INSERT
db.commit()Записать на диск
db.refresh(row)Подтянуть id, created_at

Связка с API "Заметки"

После Первая программа на FastAPI замените _notes на таблицу NoteRow и те же Pydantic-модели NoteCreate / NoteOut.


Асинхронный PostgreSQL

Синхронный Session в async def блокирует event loop. Для нагрузки — create_async_engine, AsyncSession, драйвер asyncpg — см. Асинхронность и многопоточность в Python, Работа с базами данных в Python.


Миграции Alembic

pip install alembic
alembic init alembic
alembic revision --autogenerate -m "create users"
alembic upgrade head

Разбор фрагмента:

  • alembic init создаёт инфраструктуру миграций в проекте.
  • revision --autogenerate генерирует миграцию из изменений ORM-моделей.
  • upgrade head применяет все миграции до актуальной версии схемы.

create_all() — для первого дня; в команде — только Alembic.


Типичные ошибки

ОшибкаПоследствиеЧто делать
Одна сессия на всё приложениеГонкиDepends(get_db)
Забыли commitДанные пропадают после рестартаcommit() после add
N+1Много SQL на один HTTPjoinedload / один JOIN
Секреты в gitУтечкаDATABASE_URL из .env

Сравнение с Django

Django — ORM и миграции в комплекте. FastAPI + SQLAlchemy — свобода и чистый JSON API. Выбор: Создание собственного API на Python.


Тестирование

from fastapi.testclient import TestClient
from main import app

client = TestClient(app)

def test_create_user():
r = client.post("/users", json={"username": "alice", "email": "a@b.c"})
assert r.status_code == 201

Подробнее: Тестирование на pytest.


Связанные материалы


Практика проектирования схемы

Перед созданием таблиц полезно ответить на три вопроса:

  • какие поля обязательны для бизнес-операции;
  • какие ограничения должна гарантировать сама БД (UNIQUE, NOT NULL);
  • какие индексы нужны для частых запросов.

Пример для users:

  • username и email делают уникальными;
  • created_at хранит момент создания на стороне СУБД;
  • поиск по username получает индекс, если это частый кейс.

Такой подход снижает количество ошибок, которые сложно поймать только на уровне API.


Чек-лист перед продакшеном

  • строка подключения берётся из переменных окружения;
  • миграции Alembic применяются в CI/CD, а не вручную на сервере;
  • есть сценарий отката миграции (alembic downgrade);
  • для PostgreSQL настроен пул соединений;
  • API-тесты покрывают CRUD и конфликт уникальности.

Основа по протоколу

Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.