Теперь настало время закрепить изученное на практике, используя PostgreSQL, и понять, как Alembic помогает упрощать работу с изменениями в реальном проекте.
Основная цель этой части лекции — применить миграции Alembic на практике: настроить PostgreSQL, внести изменения в существующую структуру базы данных и выполнить миграции.
Установка PostgreSQL и подключение к проекту FastAPI
Если у вас еще не настроена PostgreSQL, самое время это исправить. Для локальной работы вы можете использовать Docker (ваш лучший друг, когда речь заходит о базах данных):
docker run --name postgres_alembic_example -e POSTGRES_USER=admin -e POSTGRES_PASSWORD=admin -e POSTGRES_DB=example_db -p 5432:5432 -d postgres
Этот контейнер создаст PostgreSQL-сервер с пользователем admin, паролем admin и базой данных example_db на порту 5432.
Теперь обновим подключение к базе данных в вашем проекте FastAPI. В файле settings.py (или его аналоге) укажите:
DATABASE_URL = "postgresql+psycopg2://admin:admin@localhost:5432/example_db"
И не забудьте убедиться, что у вас установлен пакет psycopg2 для работы с PostgreSQL:
pip install psycopg2
Настройка Alembic для работы с PostgreSQL
Если Alembic уже был инициализирован в вашем проекте, просто убедитесь, что в файле alembic.ini указана правильная строка подключения к базе данных:
sqlalchemy.url = postgresql+psycopg2://admin:admin@localhost:5432/example_db
Если же Alembic еще не инициализирован, выполните команду:
alembic init alembic
Убедитесь, что файл env.py настроен для взаимодействия с вашими моделями и базой данных. Например:
from myapp.models import Base # Импортирайте ваш базовый класс из моделей
def run_migrations_online():
...
connectable = engine_from_config(
config.get_section(config.config_ini_section),
prefix="sqlalchemy.",
poolclass=pool.NullPool,
)
with connectable.connect() as connection:
context.configure(
connection=connection,
target_metadata=Base.metadata # Указываем ваши модели для анализа
)
...
Если вы пропустили настройку env.py в предыдущих лекциях, вернитесь к ним, чтобы восстановить последовательность.
Изменение структуры таблицы с помощью Alembic
Предположим, у вас уже есть таблица users в базе данных. Она может выглядеть так:
# models.py
from sqlalchemy import Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, index=True, nullable=False)
А теперь потребуется добавить новое поле age и изменить тип данных email, чтобы он стал необязательным.
Генерация миграции
Сначала изменяем нашу модель:
# models.py
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
name = Column(String, nullable=False)
email = Column(String, unique=True, index=True) # Убрали nullable=False
age = Column(Integer, nullable=True) # Новое поле для возраста
Теперь запускаем автогенерацию миграции:
alembic revision --autogenerate -m "Add age and make email nullable"
Alembic создаст файл миграции в папке alembic/versions/. Его структура примерно следующая:
def upgrade():
# команда для добавления колонок
op.add_column("users", sa.Column("age", sa.Integer(), nullable=True))
# команда для изменения существующих колонок
op.alter_column("users", "email", existing_type=sa.String(), nullable=True)
def downgrade():
# команда для отката добавленной колонки
op.drop_column("users", "age")
# команда для возврата изменения типа данных
op.alter_column("users", "email", existing_type=sa.String(), nullable=False)
Применяем изменения к базе данных:
alembic upgrade head
Теперь структура таблицы обновлена! Вы можете проверить изменения прямо из PostgreSQL:
\d users
Управление версионностью и откат изменений
Alembic позволяет легко управлять версиями миграций, архивировать историю изменений и откатывать ошибки.
Чтобы проверить текущую версию базы данных, выполните команду:
alembic current
В ответ вы увидите идентификатор миграции:
Current revision for default: <revision_id>
Если вы вдруг осознали, что добавление поля age было ошибкой (например, из-за накладных расходов), откатите миграцию:
alembic downgrade -1
После этого Alembic вернет базу данных к предыдущей версии. Для проверки снова выполните:
alembic current
Вы также можете откатываться не просто на одну ревизию, а к конкретной версии, указав её идентификатор:
alembic downgrade <revision_id>
Пример полного сценария миграций
Давайте рассмотрим последовательность задач, которые могут возникнуть в реальном проекте.
Сценарий: добавляем адрес пользователя.
Вам нужно добавить таблицу addresses, связанную с таблицей users. Это выглядит следующим образом:
# models.py
class Address(Base):
__tablename__ = "addresses"
id = Column(Integer, primary_key=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"))
address_line = Column(String, nullable=False)
city = Column(String, nullable=False)
country = Column(String, nullable=False)
Создаем миграцию для новой таблицы:
alembic revision --autogenerate -m "Create addresses table"
Файл миграции может быть следующим:
def upgrade():
op.create_table(
"addresses",
sa.Column("id", sa.Integer(), nullable=False),
sa.Column("user_id", sa.Integer(), nullable=True),
sa.Column("address_line", sa.String(), nullable=False),
sa.Column("city", sa.String(), nullable=False),
sa.Column("country", sa.String(), nullable=False),
sa.ForeignKeyConstraint(["user_id"], ["users.id"]),
sa.PrimaryKeyConstraint("id"),
)
def downgrade():
op.drop_table("addresses")
Применяем миграцию:
alembic upgrade head
Теперь у вас есть таблица addresses, связанная с таблицей users!
Частые ошибки и их решение
- "Target database is not up to date". Это происходит, если вы забыли применить миграции перед изменением структуры базы данных вручную. Убедитесь, что база данных и миграции синхронизированы.
- Ошибка подключения к базе данных. Проверьте, правильно ли указаны параметры в
alembic.ini. - Конфликты ревизий в команде. Используйте
alembic merge, если два разработчика случайно создали миграции из одного состояния базы данных, и они конфликтуют.
Управление миграциями и версиями в PostgreSQL через Alembic — это процесс, который может стать основой стабильности вашей базы данных. Теперь вы готовы к более сложным задачам и увереннее чувствуете себя при внесении изменений в проекты!
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ