Как работают миграции Django и что происходит при выполнении makemigrations vs migrate?
makemigrations читает модели и создаёт файлы миграций в коде, не трогая базу; migrate применяет эти файлы к базе, выполняя SQL и фиксируя результат в таблице django_migrations.
Миграции Django: как это работает
Миграции — механизм версионирования схемы базы данных. Django отслеживает изменения моделей и превращает их в SQL-инструкции, которые применяются к базе. Два главных шага — makemigrations и migrate — часто путают, но они делают принципиально разные вещи.
makemigrations: генерация файлов миграций
python manage.py makemigrations — читает текущее состояние моделей из кода, сравнивает с последней применённой миграцией (внутреннее состояние хранится в самих файлах миграций), и генерирует новый файл-миграцию в директории migrations/. База данных в этот момент не меняется.
# Создать миграции для всех приложений
python manage.py makemigrations
# Только для конкретного приложения
python manage.py makemigrations myapp
# Дать осмысленное имя
python manage.py makemigrations myapp --name add_user_avatar
# Посмотреть SQL без применения
python manage.py sqlmigrate myapp 0003_add_user_avatar
Что внутри файла миграции
# myapp/migrations/0003_add_user_avatar.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("myapp", "0002_alter_user_email"),
]
operations = [
migrations.AddField(
model_name="user",
name="avatar",
field=models.ImageField(null=True, blank=True, upload_to="avatars/"),
),
]
Файл декларативен: dependencies выстраивают граф порядка применения, operations — список изменений схемы.
migrate: применение миграций к базе
python manage.py migrate — читает все непримененные файлы миграций и выполняет их SQL в базе. Таблица django_migrations хранит историю применённых миграций.
# Применить все непримененные миграции
python manage.py migrate
# Применить миграции конкретного приложения
python manage.py migrate myapp
# Откатиться к конкретной миграции
python manage.py migrate myapp 0002
# Показать статус всех миграций
python manage.py showmigrations
# Показать статус конкретного приложения
python manage.py showmigrations myapp
Полный цикл: от модели до базы
# 1. Изменяем модель в models.py
class UserProfile(models.Model):
user = models.OneToOneField("auth.User", on_delete=models.CASCADE)
bio = models.TextField(blank=True) # новое поле
avatar = models.ImageField(null=True, upload_to="avatars/") # ещё одно
# 2. Генерируем файл миграции
python manage.py makemigrations myapp --name add_bio_and_avatar
# Migrations for 'myapp':
# myapp/migrations/0003_add_bio_and_avatar.py
# - Add field avatar to userprofile
# - Add field bio to userprofile
# 3. Проверяем SQL
python manage.py sqlmigrate myapp 0003_add_bio_and_avatar
# 4. Применяем
python manage.py migrate
# Applying myapp.0003_add_bio_and_avatar... OK
django_migrations: таблица учёта
Django хранит применённые миграции в таблице django_migrations (app, name, applied). При запуске migrate он сравнивает файлы в migrations/ с записями в этой таблице и применяет только отсутствующие.
Особые команды
--check: завершается с кодом 1 если есть несозданные миграции — удобно в CI.squashmigrations: сжимает много миграций в одну для оптимизации.--fake: помечает миграцию как применённую без реального выполнения SQL (нужно при ручных изменениях схемы).--fake-initial: для уже существующих таблиц при начальной интеграции.
Подводные камни
- Файлы миграций нужно коммитить в git — они часть кодовой базы. Не добавляйте
*/migrations/в .gitignore. - Конфликты миграций при работе нескольких разработчиков: два разработчика одновременно создали
0003_*.py. Решение:python manage.py makemigrations --merge. - Нельзя переименовывать файлы миграций вручную — Django ищет их по имени в
django_migrations. - Удаление поля из модели без миграции приводит к ошибкам на уровне ORM, но таблица в БД остаётся нетронутой до
migrate. makemigrationsбезmigrateничего не меняет в схеме — распространённая ошибка новичков.- Откат миграций (
migrate myapp 0002) поддерживается только если операция обратима;RunPythonбезreverse_code— необратима. - В production применять миграции нужно до деплоя нового кода, чтобы избежать рассинхронизации схемы и ORM.
Common mistakes
- Описывать migrations makemigrations vs migrate только как термин и не показывать механизм на минимальном примере.
- Игнорировать ошибки, пустые данные, конкурентный доступ или границы транзакции.
- Не связывать поведение с официальным контрактом Django и реальной эксплуатацией.
What the interviewer is testing
- Объясняет migrations makemigrations vs migrate через последовательность действий, а не через набор ключевых слов.
- Приводит короткий кодовый пример или production-сценарий с ожидаемым поведением.
- Называет хотя бы один риск: производительность, безопасность, транзакции, память или сопровождение.