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

Как откатить миграции в Django?

1.3 Junior🔥 111 комментариев
#Django#Базы данных (SQL)

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

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

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

Откат миграций в Django: Полный гайд

Откат миграций — это критический навык для разработки. Я много работал с миграциями, и вот всё, что нужно знать.

Основная команда: migrate

Откат всех миграций приложения

# Откатить все миграции приложения (вернуться в начальное состояние)
python manage.py migrate myapp zero

# Пример
python manage.py migrate users zero  # Откатывает все миграции приложения users

Откат на конкретную миграцию

# Откатить до конкретной миграции (не включая её)
python manage.py migrate myapp 0003_previous_migration

# Пример
python manage.py migrate users 0005_add_profile
# Вернётся к состоянию после миграции 0005_add_profile

Откат на N шагов назад

# К сожалению, Django не имеет встроенной команды для откатов на N шагов
# Нужно найти конкретную миграцию, но есть хитрость:

# Просмотр всех миграций
python manage.py showmigrations myapp

# Вывод примерно такой:
# users
#  [ ] 0001_initial
#  [X] 0002_add_email
#  [X] 0003_add_profile
#  [X] 0004_rename_field
#  [X] 0005_add_avatar

# Если текущее состояние — 0005, и мы хотим откатить на 2 шага (вернуться к 0003)
python manage.py migrate users 0003_add_profile

Примеры для разных ситуаций

Ситуация 1: Откатить последнюю миграцию

# Сначала смотрим, какие миграции применены
python manage.py showmigrations

# Находим, какая миграция была до текущей
# Если текущая 0005_add_avatar, и до неё была 0004_rename_field, то:
python manage.py migrate myapp 0004_rename_field

Ситуация 2: Полный откат всех миграций в БД

# ОСТОРОЖНО: Это удалит ВСЕ изменения БД!
python manage.py migrate myapp zero

# Для всех приложений
python manage.py migrate zero  # Откатывает все миграции всех приложений

Ситуация 3: Откатить миграции нескольких приложений

# Откатить приложение users до нуля
python manage.py migrate users zero

# Откатить приложение posts до миграции 0003
python manage.py migrate posts 0003_add_comments

# Откатить приложение core до нуля
python manage.py migrate core zero

Практический пример: Desenvolvimento workflow

# 1. Видим, что последняя миграция вызвала проблему
python manage.py showmigrations
# Output:
# users
#  [X] 0001_initial
#  [X] 0002_add_email
#  [X] 0003_add_profile  <- Эта вызывает ошибку

# 2. Откатываем последнюю миграцию
python manage.py migrate users 0002_add_email

# 3. Удаляем файл неправильной миграции
rm myapp/migrations/0003_add_profile.py

# 4. Создаём исправленную версию
python manage.py makemigrations users

# 5. Применяем заново
python manage.py migrate users

Состояние БД во время миграций

# migrations/0003_add_field.py
from django.db import migrations, models

class Migration(migrations.Migration):
    dependencies = [
        ('myapp', '0002_previous_migration'),
    ]
    
    operations = [
        migrations.AddField(
            model_name='user',
            name='phone',
            field=models.CharField(max_length=20, default=''),
            preserve_default=False,
        ),
    ]

Откат этой миграции: Удалит поле phone из таблицы user

Просмотр статуса миграций

# Все миграции во всех приложениях
python manage.py showmigrations

# Все миграции конкретного приложения
python manage.py showmigrations myapp

# С подробностью
python manage.py showmigrations --verbosity 2

# Только примененные
python manage.py showmigrations --list | grep '\[X\]'

# Только не примененные
python manage.py showmigrations --list | grep '\[ \]'

Проверка SQL, который будет выполнен

# Посмотреть SQL без применения
python manage.py sqlmigrate myapp 0003_add_profile

# Для отката (требует некоторой подготовки)
python manage.py sqlmigrate myapp 0003_add_profile --backwards  # Django < 3.1

Обработка проблем при откате

Проблема 1: "django.db.utils.IntegrityError: duplicate key value"

# migrations/0005_fix_migration.py
from django.db import migrations, models

def clean_duplicates(apps, schema_editor):
    """Удаляет дубликаты перед откатом"""
    User = apps.get_model('users', 'User')
    # Логика удаления дубликатов
    User.objects.filter(email='').delete()

class Migration(migrations.Migration):
    dependencies = [
        ('users', '0004_previous'),
    ]
    
    operations = [
        migrations.RunPython(clean_duplicates, migrations.RunPython.noop),
    ]

Проблема 2: Окружение развивается, откат не работает

# ОПАСНО: Принудительный откат (может привести к несогласованности)
python manage.py migrate --fake myapp zero

# Это только обновит таблицу django_migrations, не изменяя БД
# Используй только если знаешь, что делаешь!

Скрипт для удобного откатывания

#!/bin/bash
# reset_migrations.sh

if [ -z "$1" ]; then
    echo "Usage: ./reset_migrations.sh <app_name> [target_migration]"
    exit 1
fi

APP=$1
TARGET=${2:-"zero"}

echo "Rolling back migrations for app: $APP to: $TARGET"
python manage.py migrate $APP $TARGET
echo "Done!"

Проверка перед откатом

# 1. Убедитесь в резервной копии БД
pg_dump mydatabase > backup_$(date +%Y%m%d_%H%M%S).sql  # PostgreSQL
mysqldump mydatabase > backup_$(date +%Y%m%d_%H%M%S).sql  # MySQL

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

# 3. Проверьте, есть ли данные, которые будут потеряны
python manage.py dbshell
# SELECT COUNT(*) FROM users_phone;  -- Если откатываем удаление поля

# 4. Только потом откатывайте
python manage.py migrate myapp <target_migration>

Production: Безопасный откат

# На production НИКОГДА не откатывайте без подготовки!

# 1. Заблокировать приложение для новых операций
# (Используй maintenance mode)

# 2. Создать резервную копию
sudo pg_dump production_db > prod_backup_2026_03_22.sql

# 3. Откатить в отдельной ветке БД для тестирования
python manage.py migrate myapp 0002_previous_migration --database=test_backup

# 4. Если всё ок, откатить в боевой БД
python manage.py migrate myapp 0002_previous_migration

# 5. Снять блокировку

Итоговый чеклист откатывания

  • Создал резервную копию БД
  • Посмотрел showmigrations и знаю текущее состояние
  • Идентифицировал целевую миграцию для отката
  • На development — проверил откат локально
  • Выполнил команду: python manage.py migrate myapp <target>
  • Проверил, что БД теперь в правильном состоянии
  • Если нужно, удалил файлы миграций с диска
  • Создал новые миграции если потребовалось
  • Применил новые миграции: python manage.py migrate

Типичные ошибки

# ОШИБКА 1: Неправильное имя миграции
python manage.py migrate users 0002_add_email_field  # Опечатка в имени

# ОШИБКА 2: Забыли приложение
python manage.py migrate 0002_add_email  # Какое приложение?

# ОШИБКА 3: Применили откат, но модель не обновилась
# migrations откатились, но код всё ещё ссылается на удаленное поле
# Решение: Обновить код модели вручную

# ОШИБКА 4: Не учли зависимости
# Миграция 0005 зависит от 0004
# Если откатить 0004, 0005 останется висеть
python manage.py migrate myapp zero  # Откатить всё сразу

Итоговая рекомендация

В Development: Откатывай свободно, это помогает работать итеративно В Production: Никогда не откатывай — создавай новые миграции для исправления ошибок

Лучший подход: пишешь миграцию → видишь проблему → откатываешь → удаляешь файл → пишешь правильную миграцию → применяешь заново.