Архитектура Backend проекта на FastAPI и SQLAlchemy
Архитектура и Alembic
Структура проекта
Когда вы начинаете новый проект, легко поддаться искушению свалить все файлы в одну папку. Но по мере роста приложения такой подход превращается в хаос. Правильная структура — это как план здания: она помогает ориентироваться, разделять логику и упрощает поддержку в будущем.
Для FastAPI-приложений принято разделять код на логические слои. Представьте, что вы строите дом. У вас есть фундамент (модели данных), стены и комнаты (бизнес-логика и обработка запросов) и крыша с дверями (точки входа, или роуты).
Такое разделение позволяет коду быть чистым и модульным. Если вам нужно изменить что-то в базе данных, вы идете в папку models. Если нужно поправить формат ответа API — в schemas. Это делает разработку предсказуемой и быстрой.
Знакомство с Alembic
Представьте, что вы пишете книгу вместе с командой. Каждый вносит правки, добавляет и удаляет абзацы. Без системы контроля версий, как Git, вы бы быстро запутались, кто что изменил. С базами данных та же история. Схема базы данных (ее структура, таблицы, колонки) постоянно меняется в процессе разработки.
Миграция
noun
Процесс управляемого и версионируемого изменения схемы базы данных. Каждая миграция — это скрипт, который описывает, как применить (upgrade) и как отменить (downgrade) определенное изменение.
Alembic — это инструмент для управления миграциями баз данных для приложений, использующих SQLAlchemy. Он позволяет вам описывать изменения схемы базы данных в виде Python-скриптов. Эти скрипты, или «миграции», можно применять последовательно, чтобы обновить базу данных до последней версии, или откатывать, если что-то пошло не так. Это как машина времени для вашей базы данных.
Настройка Alembic
Первый шаг — инициализировать Alembic в вашем проекте. Это создаст необходимые файлы конфигурации и папку для хранения самих миграций. Выполните в терминале, находясь в корневой папке вашего проекта:
alembic init alembic
Эта команда создаст папку alembic и файл alembic.ini. Папка alembic содержит скрипты миграций и файл env.py, который является сердцем конфигурации. Файл содержит общие настройки, такие как строка подключения к базе данных.
Файл
alembic.ini— это настройки верхнего уровня. Файлenv.py— это исполняемый скрипт, который настраивает и запускает Alembic.
Асинхронная магия в env.py
FastAPI часто используется с асинхронными драйверами баз данных, такими как asyncpg для PostgreSQL. По умолчанию Alembic настроен на работу с синхронным кодом. Чтобы подружить их, нужно немного изменить файл alembic/env.py.
Сначала нужно импортировать необходимые библиотеки и указать Alembic, где искать ваши модели SQLAlchemy. Alembic должен знать о моделях, чтобы сравнивать их с текущим состоянием базы данных и автоматически генерировать миграции.
# alembic/env.py
import asyncio
from logging.config import fileConfig
from sqlalchemy import pool
from sqlalchemy.engine import Connection
from sqlalchemy.ext.asyncio import async_engine_from_config
from alembic import context
# Это импорт вашей базовой модели из проекта
# Убедитесь, что путь правильный
from my_project.models.base import Base
# ... (остальной код файла) ...
# Указываем Alembic на метаданные наших моделей
target_metadata = Base.metadata
# ... (код для получения URL базы данных) ...
Самая важная часть — это заставить Alembic выполнять миграции в асинхронном режиме. Для этого мы создаем асинхронную функцию run_migrations_online и запускаем ее с помощью asyncio.run().
# alembic/env.py
def do_run_migrations(connection: Connection) -> None:
context.configure(connection=connection, target_metadata=target_metadata)
with context.begin_transaction():
context.run_migrations()
async def run_async_migrations() -> None:
"""Запускает миграции в асинхронном режиме."""
# Получаем конфигурацию из alembic.ini
config_section = config.get_section(config.config_main_section)
# Добавляем URL базы данных из переменных окружения
config_section["sqlalchemy.url"] = get_url_from_env() # Ваша функция для получения URL
connectable = async_engine_from_config(
config_section,
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
async with connectable.connect() as connection:
await connection.run_sync(do_run_migrations)
await connectable.dispose()
def run_migrations_online() -> None:
"""Основная функция для запуска миграций."""
asyncio.run(run_async_migrations())
if context.is_offline_mode():
run_migrations_offline()
else:
run_migrations_online()
Этот код создает асинхронный «движок» SQLAlchemy, подключается к базе данных и выполняет миграции внутри асинхронного соединения. Теперь Alembic готов к работе с вашим асинхронным приложением.
Создание первой миграции
Допустим, мы создали нашу первую модель SQLAlchemy — таблицу для пользователей.
# my_project/models/user.py
from sqlalchemy import Column, Integer, String
from .base import Base
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
username = Column(String, unique=True, nullable=False)
email = Column(String, unique=True, nullable=False)
Теперь, когда модель определена, мы можем попросить Alembic сравнить ее с базой данных (которая пока пуста) и сгенерировать скрипт миграции.
alembic revision --autogenerate -m "Create users table"
Alembic создаст новый файл в папке alembic/versions/ с кодом для создания таблицы users. Этот файл будет содержать две функции: upgrade() и downgrade(). upgrade() применяет изменения, а downgrade() их отменяет.
Чтобы применить миграцию и создать таблицу в базе данных, выполните команду:
alembic upgrade head
Команда head указывает Alembic применить все миграции до самой последней версии. Ваша база данных теперь синхронизирована с вашими моделями. Если вы добавите новое поле в модель User и снова запустите autogenerate, Alembic создаст новую миграцию для добавления этого поля в таблицу.
Какова основная цель структурирования FastAPI-проекта путем разделения кода на логические слои (модели, схемы, роуты)?
Для чего используется инструмент Alembic в проектах, работающих с SQLAlchemy?
Теперь у вас есть надежный фундамент для вашего FastAPI-приложения: логичная структура файлов и мощный инструмент для управления версиями схемы базы данных. Это позволяет сосредоточиться на разработке бизнес-логики, не беспокоясь о ручном обновлении таблиц.