最後の移行を元に戻す方法は?


446

新しいテーブルを追加する移行を行ったので、新しい移行を作成せずに、それを元に戻して移行を削除したい。

どうすればいいのですか?最後の移行を元に戻すコマンドはありますか?その後、移行ファイルを削除できますか?

回答:


794

以前の移行に移行することで元に戻すことができます。

たとえば、最後の2つの移行が次の場合:

  • 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

7
私はこの問題に対するSOの多くの回答を見てきましたが、これらは古くて単に機能しなくなります。+1。これはDjango 1.8で動作するためです。
AlanSE

2
アプリに移行ファイルが1つしかない場合/初期移行の場合。最初の移行を元に戻す必要がありますか?
Adiyat Mubarak

37
migrateコマンドレットは、使用するのです./manage.py migrate my_app zeroアプリのためのすべてのマイグレーションの適用を解除します。
Alasdair

4
何らかの理由で、。/ manage.py migrate my_app 0010_previous_migrationが機能しませんでした。だから私は./manage.py migrate my_app 0010を使ってみましたが、うまくいきました。Django 1.8が完全な移行名を取らない理由は何ですか?
Varun Verma 2017

4
実際の移行名を使用している限り'0010_previous_migration'、ではありませんが、なぜそのような動作が見られるのかわかりません。
Alasdair 2017

36

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: Nonemigrations.RunPython.noop上記のスニペットで。これらはどちらも機能的には同じです。(コメントへのクレジット)


5
以降はDjango 1.8からは、あなたが使用する必要がありますRunPython.noopインラインラムダまたはequivelentの代わりに:docs.djangoproject.com/en/1.8/ref/migration-operations/...
SpoonMeiser

@SpoonMeiser例の構文では、のように見えると思いますmigrations.RunPython(forwards_func, migrations.RunPython.noop)。機能的に確認する必要があります。これは、回答または編集としていつか追加されるはずです。
AlanSE

13

上記の解決策は実際にはユースケースをカバーしていないため、これが私の解決策です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を介してテーブルにアクセスする方法のみを表示しています。


ForeignKeysを使用して新しいモデルを作成し、複数の移行を行うと、すべてが正しく認識されず、新しいモデルで同じモデル名または同じリレーションシップ名を使用して2〜3回の移行が逆方向に再開されます...このソリューションは明らかに勝者です。ように私はエラーメッセージを持っていたdjango.db.utils.ProgrammingError: relation "<relation name>" already existsので、私が作ったmigrate --fake間違っている、私は戻ってみましたので、私は持っpsycopg2.ProgrammingError: relation "<other <relation name>" does not existTHANKS
onekiloparsec

10

もう1つのことは、手動で作成したテーブルを削除することです。

それとともに、その特定の移行ファイルを削除する必要があります。また、その特定の移行に関連するdjango-migrationsテーブルの特定のエントリ(おそらく、最後のエントリ)削除する必要があります。


この場合は注意してください。dbが適切であることを確認する必要があります。
SławomirLenart

4
私は非常に慎重に追加します。制約など、Postgresで多くのことを壊す可能性があります。
joedborg 2016年

9

復帰が完了するまで移行ファイルを削除しないでください。私はこの間違いを犯しましたが、移行ファイルがないと、データベースは何を削除するかわかりませんでした。

python manage.py showmigrations
python manage.py migrate {app name from show migrations} {00##_migration file.py}

移行ファイルを削除します。目的の移行がモデルに含まれると...

python manage.py makemigrations
python manage.py migrate

8

私はこれを1.9.1で行いました(作成された最後または最新のマイグレーションを削除するため):

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

    例: rm myapp/migrations/0011*

  2. データベースにログインし、このSQL(この例ではpostgres)を実行しました

    delete from django_migrations where name like '0011%';

その後、削除したばかりの移行番号(この場合は11)から始まる新しい移行を作成することができました。


1
+1これは機能しますが、最後の手段としてこの方法を保存する必要があります。また、問題のある移行の原因となった列/テーブルを編集/削除することを忘れないでください。
ニーム

良い点-移行を作成したときにこれを使用しましたが、まだ "./manage.py migrate"を実行していませんでした
MIkee

3

この回答は、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作成します。

移行はすべてのケースA)、B)、C)、D)でDjango 1.9+を使用して作成されます(Django 1.8を使用するケースB、C、Dのみ)。ただし、適切な場合にのみデータベースに適用されます。必要です。Django 1.8以降、テストを実行するには移行が必要です。Django 1.9以降でmanaged = Falseが設定されているモデルでも、移行によって関連する完全な現在の状態が記録されます。これにより、管理対象/非管理対象モデル間にForeignKeyを作成したり、後でモデルをmanaged = Trueにしたりできます。(この質問はDjango 1.8の時点で書かれています。ここにあるすべては1.8から現在の2.2までのバージョンで有効です。)

最後の移行が簡単に元に戻せない場合は、データベースのバックアップ後に慎重に偽の元に戻し ./manage.py migrate --fake my_app 0010_previous_migration、テーブルを手動で削除することができます。

必要に応じて、固定モデルから固定マイグレーションを作成し、データベース構造を変更せずにそれを適用します./manage.py migrate --fake my_app 0011_fixed_migration


3

移行を元に戻すときに問題が発生し、なんらかの方法で問題が発生した場合は、移行を実行できますfake

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

ジャンゴバージョン<1.7これはにエントリが作成されますsouth_migrationhistoryテーブルを、あなたはそのエントリを削除する必要があります。

これで、移行を簡単に元に戻すことができます。

PS:私は長い間立ち往生していて、偽の移行を行っていましたが、元に戻すと助けになりました。


1
この回答はDjango <1.7向けです。
hynekcer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.