it-roy-ru.com

джанго отменить последнюю миграцию

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

Как мне это сделать? Есть ли команда, чтобы отменить последнюю миграцию, и тогда я могу просто удалить файл миграции?

291
Ronen Ness

Вы можете вернуться, перейдя к предыдущей миграции.

Например, если ваши последние две миграции:

  • 0010_previous_migration
  • 0011_migration_to_revert

Тогда вы бы сделали:

./manage.py migrate my_app 0010_previous_migration 

Затем вы можете удалить миграцию 0011_migration_to_revert.

Если вы используете Django 1.8+, вы можете показать имена всех миграций с помощью

./manage.py showmigrations my_app

Чтобы отменить все миграции для приложения, вы можете запустить:

./manage.py migrate my_app zero
535
Alasdair

Ответ от Alasdair охватывает основы

  • Определите миграции, которые вы хотите, с помощью ./manage.py showmigrations
  • migrate с использованием имени приложения и имени миграции

Но следует отметить, что не все миграции могут будут отменены. Это происходит, если у Django нет правила для аннулирования. Для большинства изменений, которые вы автоматически произвели с помощью ./manage.py makemigrations, будет возможно изменение. Тем не менее, пользовательские сценарии должны иметь прямую и обратную запись, как описано в следующем примере:

https://docs.djangoproject.com/en/1.9/ref/migration-operations/

Как сделать отмену операции

Если у вас была операция RunPython, то, возможно, вы просто хотите отменить миграцию без написания логически строгого сценария реверсирования. Следующий быстрый взлом к ​​примеру из документации (ссылка выше) позволяет это сделать, оставив базу данных в том же состоянии, в каком она была после применения миграции, даже после ее отмены.

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from Django.db import migrations, models

def forwards_func(apps, schema_editor):
    # We get the model from the versioned app registry;
    # if we directly import it, it'll be the wrong version
    Country = apps.get_model("myapp", "Country")
    db_alias = schema_editor.connection.alias
    Country.objects.using(db_alias).bulk_create([
        Country(name="USA", code="us"),
        Country(name="France", code="fr"),
    ])

class Migration(migrations.Migration):

    dependencies = []

    operations = [
        migrations.RunPython(forwards_func, lambda apps, schema_editor: None),
    ]

Это работает для Django 1.8, 1.9


Обновление: лучший способ написать это - заменить lambda apps, schema_editor: None на migrations.RunPython.noop во фрагменте выше. Это функционально одно и то же. (кредит к комментариям)

27
AlanSE

Другая вещь, которую вы можете сделать, это удалить таблицу, созданную вручную. 

Наряду с этим вам придется удалить этот конкретный файл миграции. Кроме того, вам придется удалить эту конкретную запись в таблице Django-migrations (возможно, последнюю в вашем случае), которая соответствует этой конкретной миграции.

8
sprksh

Вот мое решение, так как вышеупомянутое решение действительно не покрывает сценарий использования, когда вы используете RunPython.

Вы можете получить доступ к таблице через ORM с

from Django.db.migrations.recorder import MigrationRecorder

>>> MigrationRecorder.Migration.objects.all()
>>> MigrationRecorder.Migration.objects.latest('id')
Out[5]: <Migration: Migration 0050_auto_20170603_1814 for model>
>>> MigrationRecorder.Migration.objects.latest('id').delete()
Out[4]: (1, {u'migrations.Migration': 1})

Таким образом, вы можете запросить таблицы и удалить те записи, которые имеют отношение к вам. Таким образом, вы можете изменить подробно. При RynPython миграциях вам также необходимо заботиться о данных, которые были добавлены/изменены/удалены. Приведенный выше пример показывает только то, как вы получаете доступ к таблице через Djang ORM.

6
Özer S.

Я сделал это в 1.9.1 (чтобы удалить последнюю или последнюю созданную миграцию):

  1. rm <appname>/migrations/<migration #>*

    пример: rm myapp/migrations/0011*

  2. залогинился в базу данных и запустил этот SQL (в этом примере postgres)

    delete from Django_migrations where name like '0011%';

Затем я смог создать новые миграции, которые начинались с номера миграции, который я только что удалил (в данном случае, 11).

5
MIkee

Первая часть о том, как "отменить миграцию", была дана ответом Alasdair. Я отвечу:

... удалить миграцию, не создавая новую миграцию?

TL; DR: Вы можете удалить несколько последних отмененных (запутанных) миграций и создать новую после исправления моделей. Вы можете использовать другие средства для настройки , чтобы не создавать таблицу с помощью команды migrate, но необходимо создать последнюю миграцию, соответствующую текущим моделям.

«Проблемная» миграция, которая создала нежелательную таблицу, вызвана новым классом Model, который вы добавили.

Почему кто-то хочет не получить столик? Как это решить?

A) Такая таблица не должна существовать ни в одной базе данных, ни на компьютере, ни в условиях.

  • When: Это базовая модель другой модели, созданная только для наследования модели.
  • Решение: Установить class Meta: abstract = True

B) Таблица создается редко, чем-то другим или вручную особым образом.

  • Solution: Используйте class Meta: managed = False
    Миграция создается, но никогда не используется, только в тестах. Файл миграции важен, иначе тесты базы данных не могут быть запущены, начиная с воспроизводимого исходного состояния.

C) Таблица используется только на некотором компьютере (например, в разработке).

  • Solution: Переместите модель в новое приложение, которое добавляется в INSTALLED_APPS только при особых условиях, или используйте условный class Meta: managed = some_switch.

D) Проект использует несколько баз данных в settings.DATABASES

  • Решение: Напишите Маршрутизатор базы данных с методом allow_migrate, чтобы различать базы данных, где таблица может или не может быть создана.

(Я что-то забыл? Я ожидаю, что все остальное сработало для вас, только таблица не должна создаваться. Тогда, например, ошибка в параметре прокси модели может быть исключена.)

Миграция создается в случаях B), C), D) с Django 1.8 и во всех случаях ABCD с Django 1.9+, но применяется к базе данных только в соответствующих случаях или, возможно, никогда, если это необходимо. Миграции были необходимы для запуска тестов начиная с Django 1.8. Полное релевантное текущее состояние регистрируется миграциями даже для моделей с управляемого = False в Django 1.9+, чтобы можно было создать ForeignKey между управляемыми/неуправляемыми моделями или сделать модель управляемой = True позже. (Этот вопрос был написан во времена мейнстрима Django 1.8. Здесь все должно быть актуально для версий от 1.8 до текущей версии 1.11.)

2
hynekcer

Если вы столкнулись с проблемой при возврате миграции и каким-то образом испортили ее, вы можете выполнить fake миграцию.

./manage.py migrate <name> --ignore-ghost-migrations --merge --fake

Для Django версии <1.4 это создаст запись в таблице south_migrationhistory, вам нужно удалить эту запись.

Теперь вы сможете легко вернуться к миграции.

PS: я застрял на много времени, и мне пришлось выполнить ложную миграцию, а затем вернуться назад.

0
Pransh Tiwari