web-dev-qa-db-ja.com

on_deleteはDjangoモデルに対して何をしますか?

私は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は何をしますか? (ドキュメントの中のヒント

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

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

197
Marty

これは、 referenced オブジェクトが削除されたときに採用される動作です。 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に対して、この状況で予想される動作は常に自問自答する必要があります。 PROTECTSET_NULLはしばしば役に立ちます。 CASCADEを設定すべきでない場所に設定すると、単一のユーザーを削除するだけで、すべてのデータベースをカスケードで削除する可能性があります。

393
Antoine Pinsard

on_deleteメソッドは、削除するモデルインスタンスに依存するモデルインスタンスの処理方法をDjangoに伝えるために使用されます。 (ForeignKey関係など) on_delete=models.CASCADEはDjangoに削除効果をカスケードするように指示します。つまり、依存モデルも削除し続けます。

これがより具体的な例です。 Authorモデル内のForeignKeyであるBookモデルがあるとします。 Authorモデルのインスタンスを削除した場合、DjangoはBookモデルのインスタンスに依存するAuthorモデルのインスタンスの処理方法を知りません。 on_deleteメソッドはDjangoにその場合の対処法を伝えます。 on_delete=models.CASCADEを設定すると、削除効果をカスケードするようにDjangoに指示します。つまり、削除したBookモデルインスタンスに依存するすべてのAuthorモデルインスタンスを削除します。

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

これは公式の文書全体です。

31
Himank Yadav

参考までに、モデルのon_deleteパラメータは、音が逆になっています。モデルの外部キー(FK)にon_deleteを配置して、レコードでポイントしているFKエントリが削除された場合の処理​​をDjangoに指示します。当店が最も使用したオプションは、PROTECTCASCADE、およびSET_NULLです。私が考え出した基本的なルールは次のとおりです。

  1. FKが実際には変更すべきではないルックアップテーブルを指している場合、および確かにがテーブルを変更しないようにする場合は、PROTECTを使用します。誰かがそのルックアップテーブルのエントリを削除しようとすると、PROTECTは、レコードに関連付けられている場合、そのエントリが削除されないようにします。また、ルックアップテーブルのエントリを削除したという理由だけで、Djangoがyourレコードを削除しないようにします。この最後の部分は重要です。 誰かが私の性別テーブルから性別「女性」を削除する場合、その性別を持つ個人テーブルにいたすべての人を即座に削除することは決して望みません。
  2. FKが「親」レコードを指している場合は、CASCADEを使用します。そのため、Personに多数のPersonEthnicityエントリを含めることができ(彼/彼女はアメリカインディアン、黒、および白になることができます)、そのPerson isが削除された場合、私は本当にwouldが欲しいです削除する「子」PersonEthnicityエントリ。それらは人なしでは無関係です。
  3. doルックアップテーブルのエントリの削除を許可したいが、レコードを保持したい場合は、SET_NULLを使用します。たとえば、PersonがHighSchoolを持つことができるが、その高校がルックアップテーブルでなくなるかどうかは、私にとっては重要ではない場合、on_delete=SET_NULLと言います。これにより、Personレコードがそこに残ります。私のPersonの高校FKをnullに設定するだけです。明らかに、そのFKでnull=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'

最後のヒントとして、do n'ton_deleteを指定する(または指定しなかった)場合、デフォルトの動作はCASCADEであることを知っていましたか?つまり、誰かがGenderテーブルの性別エントリを削除すると、その性別のPersonレコードもすべて削除されます。

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

また、on_delete=CASCADEが選択した動作である場合、実際にはどの移行にも追加されないことに注意する価値があります。これはデフォルトだからだと思うので、on_delete=CASCADEを指定することは何も指定しないことと同じです。

29
HelenM

ここにあなたの質問に対する答えがあります:なぜ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: Cascadeは削除します。デフォルト。

PROTECT: / Django.db.IntegrityErrorのサブクラスであるProtectedErrorを送出して、参照されているオブジェクトの削除を防止する。

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

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

3
Sonia Rani

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

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」があります。また、すべての検索やリストビューなど、レポートに表示できるものや、ユーザーがフロントエンドからアクセスできるものはすべて、deleted == 1は除外します。ただし、削除されたレコードのリストをプルダウンするためのカスタムレポートまたはカスタムクエリを作成し、それが最後に変更された日時(別のフィールド)および誰によって(つまり誰がいつ削除したか)確認できます。それは実行の観点から非常に有利です。

また、それらのレコードに対してdeleted = 0のような単純な偶然の削除を元に戻すことができることを忘れないでください。

私のポイントは、機能があるのなら、それには常に理由があるということです。必ずしも良い理由ではありません。しかし理由です。そしてしばしば良いものです。

3