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

283

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

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

Теги:
django-migrations

7 ответов

536

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

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

  • 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
  • 0
    по какой-то причине это не сработало. но так как у меня был беспорядок миграции, я не уверен, что этот ответ не действителен. В любом случае, мы решили это вручную с помощью редактора sql, удалили файл миграции и заново создали миграции. Спасибо, в любом случае :)
  • 5
    Я видел много ответов на эту проблему, которые устарели и просто больше не работают. +1, потому что это работает с Django 1.8.
Показать ещё 11 комментариев
26

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

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

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

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

Как сделать отмену no-op

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

# -*- 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 в приведенном выше фрагменте. Это функционально одно и то же. (кредит на комментарии)

  • 3
    Начиная с Django 1.8, вы должны использовать RunPython.noop вместо встроенной лямбды или равнозначной: docs.djangoproject.com/en/1.8/ref/migration-operations/…
  • 0
    @SpoonMeiser В синтаксисе примера я думаю, что это выглядит как migrations.RunPython(forwards_func, migrations.RunPython.noop) . Нужно проверить это функционально. Это должно быть добавлено как ответ или редактирование этого когда-нибудь.
8

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

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

  • 0
    работал на меня ..
  • 0
    будьте осторожны в этом случае - вы обязаны проверить, соответствует ли БД.
Показать ещё 1 комментарий
5

Вот мое решение, так как вышеупомянутое решение на самом деле не распространяется на прецедент, когда вы используете 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.

  • 0
    При создании новых моделей с помощью ForeignKeys, с несколькими миграциями, понимая, что все неправильно, и перезапуская 2-3 миграции в обратном направлении, с новыми моделями, но иногда с теми же именами моделей или такими же именами отношений ... это решение явно выигрывает. У меня было сообщение об ошибке типа django.db.utils.ProgrammingError: relation "<relation name>" already exists поэтому я сделал migrate --fake - неверно, поэтому попытался вернуться назад, затем я получил psycopg2.ProgrammingError: relation "<other <relation name>" does not exist СПАСИБО
5

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

  • rm <appname>/migrations/<migration #>*

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

  • зашел в базу данных и запустил этот SQL (postgres в этом примере)

    delete from django_migrations where name like '0011%';

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

  • 0
    Я использовал этот метод, и он работает
  • 1
    +1 Хотя это сработает, вам нужно сохранить этот способ в крайнем случае. Также вы должны помнить, чтобы редактировать / удалять столбцы / таблицы, из-за которых возникла проблемная миграция.
Показать ещё 1 комментарий
2

В первой части, как "вернуть миграцию", ответил Alasdair. Я отвечу:

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

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

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

Почему кто-то может не получить таблицу? Как его решить?

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

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

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

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

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

  • Решение. Переместите модель в новое приложение, которое добавлено в 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.)

0

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

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

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

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

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

  • 1
    Этот ответ для Джанго <1,7.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню