← Назад к вопросам

Что такое фейковые миграции в Djnago?

1.8 Middle🔥 121 комментариев
#DevOps и инфраструктура#Django

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Фейковые миграции в Django

Фейковые миграции (fake migrations) — это механизм в Django для отмечания миграций как «уже применённые» без фактического выполнения их SQL кода. Это полезно для синхронизации истории миграций с текущим состоянием базы данных, когда реальные изменения были сделаны вручную или в другой системе.

Основное использование

1. Базовая команда

# Отметить миграцию как применённую БЕЗ выполнения SQL
python manage.py migrate app_name 0001_initial --fake

# Отметить конкретную миграцию
python manage.py migrate app_name 0005_change_field --fake

# Отметить все миграции как применённые
python manage.py migrate --fake

В таблице django_migrations появляется запись об этой миграции, но её SQL код не выполняется.

Практический сценарий 1: новая БД

Ситуация: вы склонировали старый проект, БД была удалена, и вам нужно привести её в актуальное состояние.

# Вариант 1: обычные миграции (долго, особенно для старых проектов)
python manage.py migrate
# Выполняет ВСЕ миграции с 0001 до текущего состояния

# Вариант 2: создать БД со свежей моделью + fake миграции
python manage.py migrate --fake-initial
# Создаёт таблицы на основе текущих models.py
# Отмечает начальную миграцию (0001_initial) как применённую
# Все остальные миграции выполняются обычно

Флаг --fake-initial наиболее полезен:

# Эквивалент:
python manage.py migrate app_name 0001_initial --fake
python manage.py migrate app_name  # остальные

Практический сценарий 2: проблема с историей миграций

Ситуация: вы вручную изменили БД (создали таблицу, добавили колонку), но Django не знает об этом.

-- Вы вручную выполнили SQL
ALTER TABLE users ADD COLUMN phone VARCHAR(20);
# После этого вы создали миграцию
# migration 0005_add_phone_field.py
class Migration(migrations.Migration):
    dependencies = [
        ('app', '0004_previous'),
    ]

    operations = [
        migrations.AddField(
            model_name='user',
            name='phone',
            field=models.CharField(max_length=20, null=True),
        ),
    ]
# Если просто выполнить миграцию, будет ошибка
python manage.py migrate
# ERROR: column "phone" already exists

# Решение: отметить как фейковую
python manage.py migrate app 0005_add_phone_field --fake
# Теперь Django знает об этой миграции, но SQL не выполняется

Практический сценарий 3: отмена и переделка

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

# Отмотать миграцию
python manage.py migrate app 0003_previous

# Удалить файл неправильной миграции
rm migrations/0004_wrong.py

# Создать новую миграцию
python manage.py makemigrations

# Применить
python manage.py migrate

Но если вы хотите переделать без откатывания:

# Создать новую миграцию (которая исправляет ошибку)
python manage.py makemigrations

# Для синхронизации: отметить старую как фейковую
python manage.py migrate app 0004_wrong --fake
python manage.py migrate app 0005_fix_wrong

Практический сценарий 4: синхронизация нескольких окружений

Ситуация: на production вы вручную применили SQL для оптимизации, но модели ещё не обновлены.

# На development: обновляем модели
# models.py изменилась

# Создаём миграцию
python manage.py makemigrations

# На production: отмечаем как фейковую (так как уже применена вручную)
ssh production
python manage.py migrate app 0006_optimization --fake
# Дальнейшие миграции:
python manage.py migrate

Как работает fake migration

# settings.py
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'mydb',
    }
}

# Таблица django_migrations (внутренняя БД Django)
# id | app | name | applied
# 1  | users | 0001_initial | 2024-01-01 10:00:00
# 2  | users | 0002_add_email | 2024-01-01 10:05:00
# 3  | users | 0003_change_phone ---> fake, SQL не выполнен!

# Код Django:
class Migration(migrations.Migration):
    # ...
    
    def run_python(self, code_func, reverse_code_func):
        # Это НЕ выполняется при --fake!
        code_func(apps, schema_editor)

Флаги, связанные с fake

--fake

Отметить конкретную миграцию как применённую БЕЗ выполнения:

python manage.py migrate myapp 0005_migration --fake

--fake-initial

Отметить первую миграцию как применённую, но основываясь на текущих моделях (вместо её реального кода):

python manage.py migrate --fake-initial
# Создаёт таблицы на основе models.py
# Отмечает 0001_initial как applied

Опасности и когда НЕ использовать --fake

Опасность 1: неконсистентность

# Вы сделали
python manage.py migrate app 0005 --fake

# Но потом забыли, и БД остаётся без изменений
# А Django думает, что миграция применена
# Это приводит к ошибкам!

Решение: сразу проверьте, что БД действительно в нужном состоянии

# Проверить состояние миграций
python manage.py showmigrations

# Проверить БД:
python manage.py dbshell
# SELECT * FROM information_schema.columns WHERE table_name = 'users';

Опасность 2: откат fake миграций

# Если вы откатываете миграцию, которая была fake
python manage.py migrate app 0004
# Django отметит 0005 как not applied
# Но реальное состояние БД не изменилось!

Правильный способ работы с fake

# 1. Убедиться, что БД действительно в нужном состоянии
python manage.py dbshell
# Проверить существование столбцов, таблиц и т.д.

# 2. Отметить миграцию как fake
python manage.py migrate app 0005_migration --fake

# 3. Проверить, что миграция отмечена
python manage.py showmigrations app
# app
#  [X] 0001_initial
#  [X] 0002_add_field
#  [X] 0003_change_field
#  [X] 0004_optimize
#  [X] 0005_migration <-- отмечена как applied

# 4. Продолжить работу
python manage.py migrate

Специальные случаи

Развёртывание нового приложения на старой БД

# На production уже есть таблицы, но Django их не знает
python manage.py migrate new_app --fake-initial
# Отмечает начальную миграцию new_app как применённую
# Дальнейшие миграции:
python manage.py migrate new_app

Слияние миграций

# Если несколько разработчиков создали конфликтующие миграции
# Вы выполнили merge

python manage.py migrate app 0005_merge
# Это просто отмечает merge как applied, БД не меняется

Проверка состояния

# Скрипт для проверки синхронизации
# manage.py shell

from django.core.management import call_command
from django.db import connection

# Получить историю миграций
from django.db import connections
from django.db.backends.base.schema import BaseSchemEditor

cursor = connection.cursor()
cursor.execute(
    "SELECT app, name, applied FROM django_migrations ORDER BY applied"
)
migrations = cursor.fetchall()
for app, name, applied in migrations:
    print(f"{app}: {name} ({applied})")

Практические советы

  • Используй --fake-initial при первом развёртывании нового проекта
  • Никогда не используй --fake без предварительной проверки БД
  • Документируй, если использовал --fake (в комментариях, в чат команде)
  • Тестируй на development перед production
  • Используй showmigrations для контроля состояния

Fake migrations — мощный инструмент для синхронизации Django и БД, но требует осторожности и понимания текущего состояния.