Что такое фейковые миграции в Djnago?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Фейковые миграции в 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 и БД, но требует осторожности и понимания текущего состояния.