Django-DB-Migrations:保留中のトリガーイベントがあるため、ALTER TABLEを実行できません


121

TextFieldからnull = Trueを削除したい:

-    footer=models.TextField(null=True, blank=True)
+    footer=models.TextField(blank=True, default='')

スキーマの移行を作成しました:

manage.py schemamigration fooapp --auto

いくつかのフッターの列が含まれているのでNULL、私はこれを取得error、私は、マイグレーションを実行する場合:

django.db.utils.IntegrityError:列 "footer"にnull値が含まれています

これをスキーマの移行に追加しました:

    for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
        sender.footer=''
        sender.save()

今私は得る:

django.db.utils.DatabaseError: cannot ALTER TABLE "fooapp_emailsender" because it has pending trigger events

なにが問題ですか?


1
この質問も同様です。stackoverflow.com / questions / 28429933 /…そして、私にとってより役立つ回答がありました。
SpoonMeiser 2017

回答:


138

これのもう1つの理由は、NOT NULL実際にすでにNULL値があるときに列を設定しようとしたためと考えられます。


7
これに対処するには、データの移行を使用するか、手動で(manage.pyシェル)行って非準拠の値を更新します
mgojohn

@mgojohnどうやってやるの?
pyramidface、2015

1
@pyramidfaceうるさすぎない場合は、djangoシェルでnull値を更新できます。より正式でテスト可能なものを探している場合、それは使用しているバージョンによって異なります。南を使用する場合は、south.readthedocs.org / en / latest / tutorial / part3.htmlを参照してください。djangoの移行を使用する場合は、こちらの「データの移行」セクションを参照してください:docs.djangoproject.com/en/1.8/topics/移行
mgojohn 2015

131

すべての移行はトランザクション内です。PostgreSQLでは、1つのトランザクションでテーブルを更新してからテーブルスキーマを変更することはできません。

データの移行とスキーマの移行を分割する必要があります。まず、このコードを使用してデータ移行を作成します。

 for sender in orm['fooapp.EmailSender'].objects.filter(footer=None):
    sender.footer=''
    sender.save()

次に、スキーマの移行を作成します。

manage.py schemamigration fooapp --auto

これで2つのトランザクションがあり、2つのステップでの移行が機能するはずです。


8
私は自分の開発マシン(PostgreSQL 9.4)でデータとスキーマの両方の変更を伴う移行を実行し、サーバー(PostgreSQL 9.1)で失敗したため、PostgreSQLはおそらくそのようなトランザクションに関する動作を変更しました。
Bertrand Bordage 2015年

1
私もほぼ同じです。それは、今日まで100以上の移行(〜20のデータ移行を含む)で問題なく機能し、その前に重複を削除するデータ移行とともに一意の一緒の制約を追加しました。PostgreSQL 10.0
LinPyファン2018

データ移行の移行でRunPython操作を使用する場合は、それが最後の操作であることを確認する必要があります。Djangoは、RunPython操作が最後の場合、独自のトランザクションを開くことを知っています。
Dougyfresh、

1
@Dougyfreshはdjangoのドキュメント化された機能ですか?
guettli

私は実際にこれをどこにも見ませんでした、私が観察したものだけでした。 docs.djangoproject.com/en/2.2/ref/migration-operations/...
Dougyfresh

9

この問題にぶつかっただけです。スキーマの移行でdb.start_transaction()およびdb.commit_transaction()を使用して、データの変更をスキーマの変更から分離することもできます。おそらく、個別のデータ移行を行うほどクリーンではありませんが、私の場合、スキーマ、データ、さらに別のスキーマ移行が必要になるため、一度にすべてを実行することにしました。


7
このソリューションの問題は次のとおりです。db.commit_transaction()の後に移行が失敗した場合はどうなりますか?これが必要な場合は、schema-mig、data-mig、schema-migの3つの移行を使用することをお勧めします。
guettli 2013

5
参照:django.readthedocs.io/en/latest/ref/migration-operations.html DDLトランザクションをサポートするデータベース(SQLiteとPostgreSQL)では、RunPython操作には、各移行用に作成されたトランザクション以外に自動的に追加されるトランザクションはありません。したがって、PostgreSQLでは、たとえば、同じ移行でスキーマの変更とRunPython操作を組み合わせないようにする必要があります。そうしないと、OperationalError:保留中のトリガーイベントがあるため、ALTER TABLE "mytable"のようなエラーが発生する可能性があります。
Iasmini Gomes 2018

5

操作で私はSET CONSTRAINTSを入れました:

operations = [
    migrations.RunSQL('SET CONSTRAINTS ALL IMMEDIATE;'),
    migrations.RunPython(migration_func),
    migrations.RunSQL('SET CONSTRAINTS ALL DEFERRED;'),
]


0

列スキーマを変更しています。そのフッター列に空白の値を含めることはできません。ほとんどの場合、その列のDBにはすでに空白の値が格納されています。Djangoは、migrateコマンドを使用して、DB内のこれらの空白行を空白から現在のデフォルト値に更新します。Djangoは、フッター列に空白の値がある行を更新し、それと同時にスキーマを変更しようとします(よくわかりません)。

問題は、値を更新しようとしているのと同じ列スキーマを同時に変更できないことです。

1つの解決策は、スキーマを更新する移行ファイルを削除することです。次に、スクリプトを実行して、これらのすべての値をデフォルト値に更新します。次に、移行を再実行してスキーマを更新します。このようにして、更新はすでに行われています。Djangoの移行はスキーマを変更するだけです。


1
いくつかのスクリプトを実行することは、私にとって本当にオプションではありません。データベースのインスタンスがいくつかあり、継続的なデプロイメントプロセスでは「manage.py migrate」を呼び出します。この質問は既に有効な回答です。
guettli
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.