DjangoJuniorTechnical

Как работают миграции 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-сценарий с ожидаемым поведением.
  • Называет хотя бы один риск: производительность, безопасность, транзакции, память или сопровождение.

Sources

Related topics