Шаг 02. База данных и миграции
⚡ Кратко: что делаем на этом шаге
Цель: Настроить Flask-Migrate (обёртка над Alembic) для управления версиями схемы БД. Вместо db.create_all() — полноценные миграции, которые можно откатить и отследить в git.
- Файлы:
app/__init__.py(уже есть),migrations/(создаётся командой) - Команды:
flask db init→flask db migrate -m "init"→flask db upgrade - Результат: папка
migrations/в git, БД создана через миграцию
🎯 Цель этапа
На этом шаге мы настраиваем Flask-Migrate — расширение, которое интегрирует Alembic
(систему миграций SQLAlchemy) в Flask-приложение. После этого изменения схемы БД
будут храниться в виде версионированных файлов миграций, а не применяться через
разрушительный db.create_all().
db.create_all() создаёт таблицы, но не умеет их изменять.
Добавили колонку в модель — create_all() ничего не сделает с уже существующей таблицей.
Миграции Alembic генерируют SQL для изменения существующей схемы
и хранят историю в git. Откатить можно командой flask db downgrade.
После этого шага у нас будет
- Папка
migrations/с конфигурацией Alembic - Flask-Migrate инициализирован в
create_app() - Первая «пустая» миграция (пока моделей нет — она просто инициализирует историю)
- Понимание цикла: изменить модель →
flask db migrate→flask db upgrade
📄 Затрагиваемые файлы
| Файл | Действие | Описание |
|---|---|---|
app/__init__.py | Уже есть | migrate уже инициализирован на шаге 01, проверяем импорты |
migrations/ | Создать (командой) | Директория Alembic — создаётся командой flask db init |
migrations/versions/ | Создать (командой) | Файлы версий миграций |
.flaskenv | Создать | Переменные для Flask CLI (FLASK_APP) |
🔨 Шаги
1. Проверяем app/__init__.py
Flask-Migrate уже подключён на шаге 01. Убеждаемся, что всё на месте:
# app/__init__.py
from flask import Flask, jsonify
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from config import config_map, Config
db: SQLAlchemy = SQLAlchemy()
migrate: Migrate = Migrate()
def create_app(config_name: str = "development") -> Flask:
app = Flask(__name__)
config_class: type[Config] = config_map[config_name]
app.config.from_object(config_class)
db.init_app(app)
migrate.init_app(app, db) # ← Flask-Migrate инициализирован здесь
@app.route("/health")
def health_check():
return jsonify({"status": "ok", "env": config_name}), 200
return app
db.init_app(app) должен идти
до migrate.init_app(app, db), потому что Migrate принимает
уже инициализированный объект db.
2. Создаём .flaskenv для Flask CLI
# .flaskenv — переменные окружения для flask CLI
# Этот файл читается python-dotenv автоматически при запуске flask
FLASK_APP=run.py
APP_ENV=development
flask db ...)
должен знать, где находится приложение. Переменная FLASK_APP=run.py
говорит Flask, какой файл импортировать. В Windows PowerShell временно задать можно:
$env:FLASK_APP = "run.py" — но .flaskenv удобнее и не теряется.
3. Инициализируем директорию миграций
flask db init
После команды появится папка migrations/:
migrations/
├── alembic.ini # конфиг Alembic
├── env.py # точка входа Alembic (редко трогают)
├── script.py.mako # шаблон для генерации файлов миграций
└── versions/ # здесь будут файлы миграций
flask db init запускают один раз при старте проекта.
Если запустить повторно — Alembic откажется создавать директорию заново.
Папку migrations/ коммитят в git вместе с кодом.
4. Создаём первую миграцию
Пока моделей нет, первая миграция будет почти пустой — она просто инициализирует
таблицу версий Alembic (alembic_version).
На шаге 03 после добавления моделей создадим «настоящую» миграцию.
flask db migrate -m "initial migration"
Alembic сгенерирует файл в migrations/versions/ с именем вида
xxxxxxxxxxxx_initial_migration.py.
5. Применяем миграцию (создаём БД)
flask db upgrade
6. Проверяем текущую версию
flask db current
🧠 Объяснение логики
Цикл работы с миграциями
- Изменяете модель (добавляете поле, таблицу, индекс)
flask db migrate -m "add field X to Question"— Alembic сравнивает модели с текущей схемой БД и генерирует файл миграции- Просматриваете сгенерированный файл в
migrations/versions/— убеждаетесь, что всё правильно flask db upgrade— применяет изменения к БД- Коммитите файл миграции в git
Откат миграции
# Откат на одну версию назад
flask db downgrade
# Откат до конкретной версии
flask db downgrade <revision_id>
# Просмотр истории миграций
flask db history
db.create_all() vs Flask-Migrate
| Характеристика | db.create_all() | Flask-Migrate |
|---|---|---|
| Создаёт таблицы | Да | Да |
| Изменяет существующие | Нет | Да |
| История изменений | Нет | Да (в git) |
| Откат | Нет | Да (downgrade) |
| Подходит для prod | Нет | Да |
db.create_all() — в тестах,
где БД в памяти (sqlite:///:memory:) создаётся заново при каждом запуске.
Для разработки и продакшна — только Flask-Migrate.
✅ Проверка
1. Проверяем структуру после init
ls migrations
2. Проверяем текущую версию
flask db current
3. Ожидаемый результат
INFO [alembic.runtime.migration] Context impl SQLiteImpl.
INFO [alembic.runtime.migration] Will assume non-transactional DDL.
INFO [alembic.runtime.migration] Running upgrade -> xxxxxxxxxxxx, initial migration
Успех flask db current:
xxxxxxxxxxxx (head)
Создан файл БД: community_pulse_dev.db в корне проекта.
Диагностика: если что-то пошло не так
- Ошибка:
Error: Could not locate a Flask application— не установлена переменнаяFLASK_APP. Проверьте.flaskenvили выполните$env:FLASK_APP = "run.py" - Ошибка:
Directory migrations already exists—flask db initуже выполнялась. Удалите папкуmigrations/или пропустите этот шаг - Ошибка:
Target database is not up to date— сначала выполнитеflask db upgrade
➡️ Что дальше
На следующем шаге создаём модели Question и Response
с современным синтаксисом SQLAlchemy 2.x: Mapped[T] и mapped_column().
После этого запустим flask db migrate ещё раз — и получим «настоящую» миграцию
с реальными таблицами.
- Готово: Flask-Migrate настроен, первая миграция применена, структура
migrations/в git - Далее (шаг 03): модели Question и Response с Mapped/mapped_column, relationship, миграция таблиц