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


348

私は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ますか?(ドキュメンテーションのヒント

他にどのようなオプションがありますか(私の推測が正しい場合)?

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



1
この同様の質問からのテキストが、この回答の以下にリストされています。「FYI、モデルのon_deleteパラメータは、それがどのように聞こえるかとは逆です。」それは元の答えよりもはるかに詳細を提供します。
HelenM

回答:


778

これは、参照先のオブジェクトが削除されたときに採用する動作です。これはdjangoに固有のものではなく、これはSQL標準です。

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

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

ソース:Djangoドキュメント

たとえば、PostGreSQLのドキュメントも参照してください。

ほとんどの場合、これCASCADEは予想される動作ですが、ForeignKeyごとに、この状況で予想される動作を常に自問する必要があります。PROTECTそしてSET_NULL、しばしば有用です。CASCADE必要のない場所を設定すると、単一のユーザーを削除するだけで、すべてのデータベースがカスケードで削除される可能性があります。


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

CASCADE行動の方向が多くの人にはっきりしないことに気づくのはおかしいです。実際、アクションだけCASCADE明確でないことに気付くのはおかしいです。カスケード動作はわかりにくいかもしれませんが、他のアクションと同じ方向であると考える必要があります。したがって、CASCADE方向が明確でないと感じた場合、それは実際にはon_delete行動が明確でないことを意味します。

データベースでは、外部キーは基本的に整数フィールドで表され、その値は外部オブジェクトの主キーです。エントリーarticle_Bへの外部キーを持つエントリーcomment_Aがあるとします。あなたは、エントリを削除した場合COMMENT_Aを、すべてが正常である、article_Bはなしでは生きするために使用COMMENT_A、それが削除されます場合は気にしないでください。ただし、article_Bを削除すると、comment_Aがパニックになります。それはarticle_Bなしでは決して生きられず、それを必要としました、それはその属性の一部です(article=article_Bしかし、* article_B **とは何ですか???)。これは、on_deleteこの整合性エラーを解決する方法を決定するための手順です、次のように言います。

  • 「いいえ!お願い!しないで!あなたなしでは生きられない!」(これはPROTECTSQL言語で言われています)
  • 「よし、私があなたのものでないなら、私は誰のものでもない」(言われているSET_NULL
  • 「さようならの世界、article_Bなしでは生きられない」そして自殺します(これがCASCADE振る舞いです)。
  • 「大丈夫です。私には予備の恋人がいますこれからarticle_Cを参照します」SET_DEFAULTまたはSET(...))。
  • 「現実に立ち向かうことはできません。たとえそれが私に残された唯一のものであっても、私はあなたの名前を呼び続けます!」DO_NOTHING

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


19
ばかげた質問ですが、カスケードは常に1つの方向性を持つべきでしょうか?つまりCommentBlogPostBlogPostを削除するための外部キーがある場合、コメントは削除されますが、RDMSに関係なく、コメントを削除してもBlogPostは削除されません。
アンソニーマニング-フランクリン

20
@AnthonyManningFranklinもちろん。削除時は、参照が「壊れている」場合にのみトリガーされます。参照を同時に削除するため、コメントを削除する場合はそうではありません。
Antoine Pinsard 2017年

6
問題はばかげたことではありません。私もその説明が必要です。したがって、ここでは関係が片側であり、関係の所有者はCommentであり、テーブルにFKフィールドがあると仮定しますが、現実のモデルについて話す場合はをBlogPost所有しCommentます。良い。
WesternGun 2018

3
注意すべき重要な点は、Djangoでon_deleteを設定しても、データベース自体にON DELETE句が作成されないことです。指定された動作(CASCADEなど)は、Djangoを介して実行される削除にのみ影響し、データベースで直接行われるraw削除には影響しません。
JoeMjr2

2
素晴らしい説明。私から賛成票をもらいます!
Homunculus Reticulli

42

このon_deleteメソッドは、削除するモデルインスタンスに依存するモデルインスタンスをどうするかをDjangoに指示するために使用されます。(例えば、ForeignKey関係)。on_delete=models.CASCADEつまりは良くとして依存モデルの削除を続ける削除効果をカスケード接続するためにはDjangoに指示します。

これはより具体的な例です。あなたが持っていると仮定しAuthorているモデルForeignKeyBookモデルを。これで、Authorモデルのインスタンスを削除すると、Djangoは、そのBookモデルのインスタンスに依存するモデルのインスタンスをどうするかを認識できなくなりますAuthoron_deleteこの方法は、そのような場合には何をすべきかをDjangoに伝えます。設定on_delete=models.CASCADEはDjangoに削除効果をカスケードするように指示します。つまり、削除したBookモデルインスタンスに依存するすべてのAuthorモデルインスタンスを削除します。

注:on_deleteDjango 2.0では必須の引数になります。古いバージョンでは、デフォルトでになっていCASCADEます。

これが公式ドキュメント全体です。


37

ちなみに、on_deleteモデルのパラメータは、それがどのように聞こえるかとは逆です。あなたは入れてon_delete、あなたの記録にを指していることFKエントリが削除された場合にどうするかをDjangoに伝えるためにモデルに外部キー(FK)に。当店はほとんどを使用しているオプションがありPROTECTCASCADESET_NULL。ここに私が考え出した基本的なルールがあります:

  1. 使用PROTECTあなたのFKが本当に変化していることをすべきではないことをルックアップテーブルを指している確かに変更にあなたのテーブルが発生することはありません。誰かがそのルックアップテーブルのエントリを削除しようとした場合PROTECT、レコードに関連付けられている場合は削除できません。また、ルックアップテーブルのエントリを削除したからといって djangoがレコードを削除するのを防ぎます。この最後の部分は重要です。 誰かが私の性別テーブルから性別「女性」を削除した場合、私はその性別を持っていた私の個人テーブルにいたすべての人々を即座に削除したくありません。
  2. CASCADEFKが「親」レコードを指している場合に使用します。人が多くPersonEthnicityエントリを持つことができるのであれば、(彼/彼女はアメリカインディアン、ブラック、ホワイト可能)、及び人がいることをされて削除された、私は本当にだろう任意の「子」PersonEthnicityエントリを削除することにしたいです。それらは人なしでは無関係です。
  3. 他のユーザーにルックアップテーブルのエントリの削除を許可したいが、それでも記録を保持たいSET_NULL場合に使用します。たとえば、PersonがHighSchoolを持つことができても、その高校が私のルックアップテーブルでなくなっても、私にはそれほど問題ではない場合、私はと言います。これは私の人の記録をそこに残します。私のPersonの高校のFKをnullに設定するだけです。明らかに、そのFK を許可する必要があります。on_delete=SET_NULLnull=True

3つのことすべてを行うモデルの例を次に示します。

class PurchPurchaseAccount(models.Model):
    id = models.AutoField(primary_key=True)
    purchase = models.ForeignKey(PurchPurchase, null=True, db_column='purchase', blank=True, on_delete=models.CASCADE) # If "parent" rec gone, delete "child" rec!!!
    paid_from_acct = models.ForeignKey(PurchPaidFromAcct, null=True, db_column='paid_from_acct', blank=True, on_delete=models.PROTECT) # Disallow lookup deletion & do not delete this rec.
    _updated = models.DateTimeField()
    _updatedby = models.ForeignKey(Person, null=True, db_column='_updatedby', blank=True, related_name='acctupdated_by', on_delete=models.SET_NULL) # Person records shouldn't be deleted, but if they are, preserve this PurchPurchaseAccount entry, and just set this person to null.

    def __unicode__(self):
        return str(self.paid_from_acct.display)
    class Meta:
        db_table = u'purch_purchase_account'

最後の一口として、指定しない場合on_delete(または指定しない場合)のデフォルトの動作は次のとおりCASCADEです。これは、誰かが性別テーブルの性別エントリを削除した場合、その性別のすべての個人レコードも削除されたことを意味します!

私は、「疑わしい場合は、設定してくださいon_delete=models.PROTECT。」次に、アプリケーションをテストします。データを危険にさらすことなく、どのFKに他の値のラベルを付ける必要があるかをすばやく理解できます。

また、それon_delete=CASCADEが選択している動作である場合、実際にはどのマイグレーションにも追加されないことに注意してください。これはデフォルトなので、置くことon_delete=CASCADEは何も置かないことと同じです。


12

前述のように、CASCADEは外部キーを持つレコードを削除し、削除された別のオブジェクトを参照します。たとえば、不動産のWebサイトがあり、都市を参照するプロパティがある場合

class City(models.Model):
    # define model fields for a city

class Property(models.Model):
    city = models.ForeignKey(City, on_delete = models.CASCADE)
    # define model fields for a property

これで、都市がデータベースから削除されると、関連するすべてのプロパティ(その都市にある不動産など)もデータベースから削除されます

次に、SET_NULL、SET_DEFAULT、DO_NOTHINGなどのオプションのメリットについても触れておきます。基本的に、管理の観点からは、これらのレコードを「削除」する必要があります。しかし、あなたは本当にそれらが消えることを望んでいない。多くの理由で。誰かが誤って、または監査と監視のためにそれを削除した可能性があります。そして明白な報告。そのため、プロパティを市から「切断」する方法になる場合があります。繰り返しますが、それはあなたのアプリケーションがどのように書かれているかに依存します。

たとえば、一部のアプリケーションには0または1の「削除済み」フィールドがあります。すべての検索やリストビューなど、レポートに表示される可能性のあるもの、またはユーザーがフロントエンドからアクセスできる場所であれば、すべて除外されますdeleted == 1。ただし、カスタムレポートまたはカスタムクエリを作成して、削除されたレコードのリストをプルダウンし、さらにそれが最後に変更された日時(別のフィールド)と誰が(つまり、誰がいつ削除したか)を確認したとします。これは、エグゼクティブの観点から非常に有利です。

またdeleted = 0、これらのレコードと同じくらい簡単に、誤って削除してしまう可能性があることを忘れないでください。

私のポイントは、機能がある場合、常にその背後に理由があるということです。常に正当な理由があるとは限りません。しかし、理由。そして、しばしば良いものも。


3
CASCADEが発生する方向が明確になったため、これは役に立ちました。SQLカスケードに慣れていない場合、受け入れられる答えは明確ではありません。
codescribblr

ありがとうございます:)ありがたいです!
George Mogilevsky

2
それは関係モデルに方向についての私の疑問を応答しますので、私はこの答えをupvote
edepe

6

ここにあなたの質問に対する答えがあります:なぜ私たちはon_deleteを使うのですか?

ForeignKeyによって参照されるオブジェクトが削除されると、DjangoはデフォルトでSQL制約ON DELETE CASCADEの動作をエミュレートし、ForeignKeyを含むオブジェクトも削除します。この動作は、on_delete引数を指定することでオーバーライドできます。たとえば、null許容のForeignKeyがあり、参照先のオブジェクトが削除されたときにそれをnullに設定する場合:

user = models.ForeignKey(User, blank=True, null=True, on_delete=models.SET_NULL)

on_deleteに使用できる値は、django.db.modelsにあります。

CASCADE:カスケード削除。デフォルト。

保護: django.db.IntegrityErrorのサブクラスであるProtectedErrorを発生させることにより、参照オブジェクトの削除を防ぎます。

SET_NULL: ForeignKeyをnullに設定します。これはnullがTrueの場合にのみ可能です。

SET_DEFAULT: ForeignKeyをデフォルト値に設定します。ForeignKeyのデフォルトを設定する必要があります。


私もsqlとdjangoを熟知していないので、単純な言葉でわかりやすくなります。ありがとうございました。
wm.p1us

2

あなたは二つのモデル、という名前の1持っていると言うと名前の別の会社を

定義上、1人で複数の会社を作成できます。

会社には1人の人物しか存在できないことを考えると、人物が削除されると、その人物に関連付けられているすべての会社も削除されるようにしたいと考えています。

したがって、まず、次のようなPersonモデルを作成します。

class Person(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.id+self.name

次に、企業モデルは次のようになります。

class Companies(models.Model):
    title = models.CharField(max_length=20)
    description=models.CharField(max_length=10)
    person= models.ForeignKey(Person,related_name='persons',on_delete=models.CASCADE)

on_delete=models.CASCADEモデル会社での使用に注意してください。それを所有する人(クラスPersonのインスタンス)が削除されると、すべての会社が削除されます。


1

既存のカスケード(つまり、滝)にFKを追加することを考えることによって、「CASCADE」の機能のメンタルモデルの方向を変えます。この滝の源は主キーです。フローダウンを削除します。

したがって、FKのon_deleteを「CASCADE」として定義すると、このFKのレコードは、PKから発生する削除のカスケードに追加されます。FKのレコードは、このカスケードに参加する場合としない場合があります( "SET_NULL")。実際、FKを含むレコードは、削除のフローを妨げる可能性さえあります。「PROTECT」でダムを建てましょう。


0

CASCADEを使用するということは、実際にDjangoに参照されたレコードを削除するように指示することを意味します。以下の投票アプリの例:「質問」が削除されると、この質問の選択肢も削除されます。

例:質問:どのように私たちについて知りましたか?(選択肢:1.友達2.テレビ広告3.検索エンジン4.メールプロモーション)

この質問を削除すると、これらの4つの選択肢もすべてテーブルから削除されます。 それが流れる方向に注意してください。問題モデルのon_delete = models.CASCADEをChoiceに置く必要はありません。

from django.db import models



class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.dateTimeField('date_published')

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_legth=200)
    votes = models.IntegerField(default=0)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.