Как Django определяет порядок применения миграций?

Ответ

Django определяет порядок применения миграций путем построения графа зависимостей (dependency graph). Этот механизм гарантирует, что изменения в базе данных применяются в правильной последовательности, даже при работе с несколькими приложениями.

Ключевой элемент — атрибут dependencies

Каждый файл миграции, сгенерированный командой python manage.py makemigrations, содержит класс Migration с атрибутом dependencies. В этом списке указываются миграции, которые должны быть применены до текущей.

Пример файла миграции 0002_add_author_bio.py:

# myapp/migrations/0002_add_author_bio.py
from django.db import migrations, models

class Migration(migrations.Migration):

    # Эта миграция зависит от самой первой миграции в этом же приложении
    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='author',
            name='bio',
            field=models.TextField(default=''),
        ),
    ]

Как это работает:

  1. Генерация: При создании новой миграции Django автоматически определяет, от каких предыдущих миграций она зависит (обычно от последней в том же приложении), и записывает это в dependencies.
  2. Выполнение: Команда python manage.py migrate сначала строит полный граф всех миграций во всех приложениях проекта. Затем она проходит по этому графу в топологическом порядке, применяя сначала те миграции, у которых нет неудовлетворенных зависимостей.

Важные моменты:

  • Имена файлов: Номера в именах файлов (0001_, 0002_) служат для удобства разработчиков и помогают избежать конфликтов имен, но не являются основным механизмом определения порядка. Главное — это dependencies.
  • Межприложенные зависимости: Если модель в одном приложении (app_b) имеет ForeignKey на модель в другом (app_a), Django автоматически создаст зависимость миграции app_b от миграции app_a.
  • Конфликты: Если два разработчика одновременно создают миграции в одной ветке, может возникнуть конфликт. Django обнаружит это и предложит объединить их с помощью команды python manage.py makemigrations --merge.

Ответ 18+ 🔞

А, ну это же про то, как Джанга решает, в каком порядке эти ваши миграции в базу пихать! Без этого, блядь, был бы полный пиздец, если бы она начала таблицы создавать, пока на них ссылаться не на что, ёпта.

Короче, у неё там в голове, то есть в коде, граф зависимостей строится. Это чтобы всё по полочкам, в правильной очереди, как в столовой при совке — сначала тарелку, потом пюреху, а не наоборот, блядь.

Всё крутится вокруг одного — атрибута dependencies

Каждая эта файлина миграции, которую команда makemigrations высирает, содержит класс. И в нём есть этот самый список dependencies. Туда записывается, какие миграции должны быть применены до того, как эта начнёт свою грязную работу.

Смотри, вот пример файла 0002_add_author_bio.py:

# myapp/migrations/0002_add_author_bio.py
from django.db import migrations, models

class Migration(migrations.Migration):

    # Эта миграция зависит от самой первой миграции в этом же приложении
    dependencies = [
        ('myapp', '0001_initial'),
    ]

    operations = [
        migrations.AddField(
            model_name='author',
            name='bio',
            field=models.TextField(default=''),
        ),
    ]

Как это всё под капотом происходит, ёпта:

  1. Рождение миграции: Когда ты говоришь "сделай миграции", Джанга не просто так файл создаёт. Она смотрит, от чего эта хрень зависит (обычно от последней миграции в том же приложении), и честно записывает это в dependencies. Не обманывает, сука.
  2. Применение: А вот когда ты команду migrate даёшь, тут начинается магия. Сначала она строит этот самый граф из ВСЕХ миграций ВСЕХ приложений. Потом начинает обходить его в топологическом порядке — то есть сначала те, у кого все "долги" (зависимости) уже выполнены. Как в игре "паутинка", блядь. Пока первую не сделаешь, ко второй не приступишь.

А теперь, блядь, важные нюансы, чтобы не облажаться:

  • Циферки в названии файла (0001_, 0002_): Это для нашего, человеческого удобства, чтобы не путаться. Но Джанге похуй на эти цифры, ей главное — список dependencies. Можно хоть 0005_ сделать первой, если зависимости указаны верно, но зачем так жить, а?
  • Зависимости между приложениями: Если в приложении app_b модель тычет ForeignKey в модель из app_a, то Джанга сама, хитрая жопа, создаст зависимость миграций app_b от миграций app_a. Автоматом, блядь! Чтобы не получилось, что ссылаемся на то, чего ещё нет. Это же логично, ёпта.
  • Конфликты, ебать: Если вы с коллегой одновременно в разных ветках наделаете миграций, а потом сольёте — будет весело, пизда. Джанга это увидит и скажет что-то вроде "ребята, вы ебанутые, у вас тут два разных 0003_". И предложит вам их слить командой python manage.py makemigrations --merge. Вот так вот, нахуй.