Django モデルで on_delete は何をしますか? 質問する

Django モデルで on_delete は何をしますか? 質問する

私は Django にかなり精通していますが、最近、on_delete=models.CASCADEモデルにオプションがあることに気付きました。それに関するドキュメントを検索しましたが、以下のもの以外は見つかりませんでした。

Django 1.9 での変更点:

on_delete2 番目の位置引数として使用できるようになりました (以前は通常、キーワード引数としてのみ渡されていました)。これは Django 2.0 では必須の引数になります。

使用例は以下の通りです。:

from django.db import models

class Car(models.Model):
    manufacturer = models.ForeignKey(
        'Manufacturer',
        on_delete=models.CASCADE,
    )
    # ...

class Manufacturer(models.Model):
    # ...
    pass

on_delete は何をしますか? (モデルが削除された場合に実行されるアクションだと思います。)

models.CASCADEをするのですか? (ドキュメントにヒントはありますか)

他にどのようなオプションが利用可能ですか (私の推測が正しければ)?

これに関するドキュメントはどこにありますか?

ベストアンサー1

これは参照されたオブジェクトが削除されたときに採用される動作です。これは Django に固有のものではなく、SQL 標準です。ただし、Django には SQL の上に独自の実装があります。(1)

このようなイベントが発生した場合に実行できるアクションは 7 つあります。

  • CASCADE: 参照されているオブジェクトが削除されると、そのオブジェクトへの参照を持つオブジェクトも削除されます (たとえば、ブログの投稿を削除する場合は、コメントも削除する必要があります)。同等の SQL: CASCADE.
  • PROTECT: 参照されたオブジェクトの削除を禁止します。削除するには、それを参照するすべてのオブジェクトを手動で削除する必要があります。同等の SQL: RESTRICT.
  • RESTRICT: (Django 3.1で導入)PROTECT SQLをRESTRICTより正確に一致させるのと同様の動作です。(Django ドキュメントの例
  • SET_NULL: 参照を NULL に設定します (フィールドは null 値を許可する必要があります)。たとえば、ユーザーを削除するときに、そのユーザーがブログ投稿に投稿したコメントは保持したいが、そのコメントは匿名 (または削除済み) ユーザーによって投稿されたとしたい場合があります。SQL の同等物: SET NULL.
  • SET_DEFAULT: デフォルト値を設定します。同等の SQL: SET DEFAULT.
  • SET(...): 指定された値を設定します。これは SQL 標準の一部ではなく、完全に Django によって処理されます。
  • DO_NOTHING: これはデータベースの整合性に問題を引き起こす可能性があるため、おそらく非常に悪い考えです (実際には存在しないオブジェクトを参照する)。SQL の同等物: NO ACTION. (2)

ソース:Django ドキュメント

参照PostgreSQLのドキュメント例えば。

ほとんどの場合、CASCADEは予想される動作ですが、すべての ForeignKey について、この状況で予想される動作は何かを常に自問する必要があります。PROTECTおよび はSET_NULL多くの場合役立ちます。 設定CASCADEすべきでない設定では、単一のユーザーを削除するだけで、データベース全体が連鎖的に削除される可能性があります。


カスケードの方向を明確にするための追加メモ

アクションの方向がCASCADE多くの人に明確でないことに気づくのは面白いことです。実際には、アクションだけが明確でないことに気づくのは面白いことです。カスケードCASCADE動作が混乱を招く可能性があることは理解していますが、他のアクションと同じ方向であるCASCADEと考えなければなりません。したがって、方向が明確でないと感じる場合は、実際にon_deleteは動作が明確でないことを意味します。

データベースでは、外部キーは基本的に、値が外部オブジェクトの主キーである整数フィールドによって表されます。エントリcomment_Aがあり、このエントリがエントリarticle_Bへの外部キーを持っているとします。エントリcomment_Aを削除しても、すべて問題ありません。article_Bcomment_Aがなくても機能していたため、削除されても問題ありません。しかし、article_B を削除すると、comment_A はパニックに陥ります。これはarticle_Bなしでは機能したことがなく、article_B を必要としており、その属性の一部です ( 、しかしarticle_Barticle=article_Bとは何でしょうか?)。ここで が介入し、次のようにしてこの整合性エラーを解決する方法を決定します。on_delete

  • 「ダメ!お願い!やめて!あなたなしでは生きていけない!」 ( Django/SQL でPROTECT言う)RESTRICT
  • 「わかった、もし私があなたのものでないなら、私は誰のものでもない」(そう言われるSET_NULL
  • 「さようなら世界、私は article_B なしでは生きていけない」と言って自殺する(これがCASCADE行動です)。
  • 「大丈夫、私には予備の恋人がいるから、今から article_C を参考にするよ」SET_DEFAULT、あるいはSET(...))。
  • 「現実を直視できない、たとえそれが私に残された唯一のことであっても、私はあなたの名前を呼び続ける!」DO_NOTHING

カスケードの方向がより明確になることを願っています。 :)


脚注

(1) DjangoはSQLの上に独自の実装を持っています。そして、下のコメントで@JoeMjr2が言及しましたDjangoはSQL制約を作成しません。制約をデータベースで確実にしたい場合(たとえば、データベースが別のアプリケーションで使用されている場合や、データベースコンソールで時々ハングしている場合など)、関連する制約を手動で設定する必要があります。オープンチケットDjango でデータベース レベルの削除制約のサポートを追加します。

(2)実際に、が役立つケースが 1 つありますDO_NOTHING。Django の実装をスキップして、データベース レベルで制約を自分で実装する場合です。

おすすめ記事