[解決済み] Django のモデルで on_delete は何をするのですか?
質問
私は 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)
こちらもご覧ください PostgreSQLのドキュメント などがあります。
ほとんどの場合
CASCADE
は期待される動作ですが、すべてのForeignKeyについて、この状況で期待される動作は何か、常に自問自答する必要があります。
PROTECT
と
SET_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 の実装をスキップして、データベースレベルで自分で制約を実装したい場合です。
関連
-
Pythonの@decoratorsについてまとめてみました。
-
[解決済み] _tkinter.TclError: 表示名がなく、$DISPLAY環境変数もない。
-
[解決済み】なぜ「LinAlgError: Grangercausalitytestsから「Singular matrix」と表示されるのはなぜですか?
-
[解決済み】numpy: true_divide で無効な値に遭遇
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] パラメータに**(ダブルスター/アスタリスク)、*(スター/アスタリスク)がありますが、これはどういう意味ですか?
-
[解決済み】if __name__ == "__main__": は何をするのでしょうか?
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み】Djangoでnull=Trueとblank=Trueの違いは何ですか?
-
[解決済み】Pythonに三項条件演算子はありますか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PythonによるLeNetネットワークモデルの学習と予測
-
pythonを使ったオフィス自動化コード例
-
Python カメの描画コマンドとその例
-
Python百行で韓服サークルの画像クロールを実現する
-
Python interpreted model libraryによる機械学習モデル出力の可視化 Shap
-
風力制御におけるKS原理を深く理解するためのpythonアルゴリズム
-
Pythonショートビデオクローラーチュートリアル
-
Python LeNetネットワークの説明とpytorchでの実装
-
[解決済み】DataFrameのコンストラクタが正しく呼び出されない!エラー
-
[解決済み】 NameError: グローバル名 'xrange' は Python 3 で定義されていません。