1. ホーム
  2. python

[解決済み] Django のモデルで on_delete は何をするのですか?

2022-03-17 18:15:06

質問

私は Django にかなり詳しいのですが、最近になって on_delete=models.CASCADE というオプションがあります。同じようにドキュメントを探したのですが、それ以上のものは見つかりませんでした。

Django 1.9で変更されました。

on_delete が 2 番目の位置引数として使用できるようになりました (以前は通常キーワード引数としてのみ渡されていました)。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 を行うか?( ドキュメントにヒントがある場合 )

他にどんなオプションがあるか( 私の推測が正しければ )?

そのためのドキュメントはどこにあるのでしょうか?

どのように解決するのですか?

のときに採用する動作です。 参照 オブジェクトが削除されました。これは 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について、この状況で期待される動作は何か、常に自問自答する必要があります。 PROTECTSET_NULL が便利なことが多い。設定方法 CASCADE を使用しない場合、ユーザーを1人削除するだけで、データベースをカスケードですべて削除してしまう可能性があります。


カスケードの方向性を明確にするための追記

の向きが変わっていることに気がつくと面白いですね。 CASCADE アクションは、多くの人にとって明確ではありません。実は、それに気づくのは面白いことで だけ CASCADE アクションが明確ではありません。カスケード動作が分かりにくいのは分かりますが 他のアクションと同じ方向です。 . したがって、もしあなたが CASCADE の方向がよくわからないということは、実は on_delete の動作が明確でない。

データベースでは、外部キーは基本的に整数値のフィールドで表され、その値は外部オブジェクトの主キーとなります。たとえば、次のようなエントリーがあるとしましょう。 コメント_A を外部キーとし、その外部キーはエントリ 記事_B . エントリを削除すると コメント_A であれば、すべて問題ありません。 記事_B を使わずに生活していた。 コメント_A で、削除されても気にしないでください。しかし、削除すると 記事_B ということで コメント_A パニック それは、決して 記事_B を必要とし、その属性の一部である( article=article_B とはいえ、何が 記事_B ???). これは on_delete をどのように解決するかを決定するために、この 完全性エラー と言うかのどちらかです。

  • ダメ!お願い!やめてくれ!あなたなしでは生きていけないの!" (これは PROTECT または RESTRICT を Django/SQL で使用する場合)
  • わかった、私があなたのものでないなら、私は誰のものでもない。 (これは SET_NULL )
  • "さようなら世界、私は記事_B"なしでは生きていけないのです。 を実行し、自殺する(これは CASCADE の動作)。
  • "大丈夫、恋人は余っているし、これからはarticle_Cを参考にしよう" ( SET_DEFAULT または、さらに SET(...) ).
  • "現実を直視できない私は、それしか残されていなくても、あなたの名前を呼び続けます!" ( DO_NOTHING )

カスケードの方向性が明確になるといいのですが... :)


脚注

(1) DjangoはSQLの上に独自の実装をしています。そして 以下のコメントで @JoeMjr2 さんが言及されています。 Django は SQL 制約を作成しません。もし、制約がデータベースによって保証されることを望むなら (例えば、データベースが他のアプリケーションによって使用されている場合、あるいは、時々データベースコンソールにぶら下がる場合)、関連する制約を自分で手動で設定したいかも知れません。そこには オープンチケット を追加し、Django のデータベースレベルの削除制約をサポートするようにしました。

<ブロッククオート

(2) 実は、1つだけ、以下のようなケースがあります。 DO_NOTHING は便利です。Django の実装をスキップして、データベースレベルで自分で制約を実装したい場合です。