No history yet

Архитектура и 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 создаст новую миграцию для добавления этого поля в таблицу.

Quiz Questions 1/6

Какова основная цель структурирования FastAPI-проекта путем разделения кода на логические слои (модели, схемы, роуты)?

Quiz Questions 2/6

Для чего используется инструмент Alembic в проектах, работающих с SQLAlchemy?

Теперь у вас есть надежный фундамент для вашего FastAPI-приложения: логичная структура файлов и мощный инструмент для управления версиями схемы базы данных. Это позволяет сосредоточиться на разработке бизнес-логики, не беспокоясь о ручном обновлении таблиц.