私は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
は何をしますか? (ドキュメントの中のヒント)
他にどのようなオプションがありますか(私の推測が正しい場合)?
このドキュメントはどこにありますか?
これは、 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に対して、この状況で予想される動作は常に自問自答する必要があります。 PROTECT
とSET_NULL
はしばしば役に立ちます。 CASCADE
を設定すべきでない場所に設定すると、単一のユーザーを削除するだけで、すべてのデータベースをカスケードで削除する可能性があります。
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
です。
参考までに、モデルのon_delete
パラメータは、音が逆になっています。モデルの外部キー(FK)にon_delete
を配置して、レコードでポイントしているFKエントリが削除された場合の処理をDjangoに指示します。当店が最も使用したオプションは、PROTECT
、CASCADE
、およびSET_NULL
です。私が考え出した基本的なルールは次のとおりです。
PROTECT
を使用します。誰かがそのルックアップテーブルのエントリを削除しようとすると、PROTECT
は、レコードに関連付けられている場合、そのエントリが削除されないようにします。また、ルックアップテーブルのエントリを削除したという理由だけで、Djangoがyourレコードを削除しないようにします。この最後の部分は重要です。 誰かが私の性別テーブルから性別「女性」を削除する場合、その性別を持つ個人テーブルにいたすべての人を即座に削除することは決して望みません。CASCADE
を使用します。そのため、Personに多数のPersonEthnicityエントリを含めることができ(彼/彼女はアメリカインディアン、黒、および白になることができます)、そのPerson isが削除された場合、私は本当にwouldが欲しいです削除する「子」PersonEthnicityエントリ。それらは人なしでは無関係です。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
を指定することは何も指定しないことと同じです。
ここにあなたの質問に対する答えがあります:なぜ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のデフォルト値を設定する必要があります。
前述のように、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
のような単純な偶然の削除を元に戻すことができることを忘れないでください。
私のポイントは、機能があるのなら、それには常に理由があるということです。必ずしも良い理由ではありません。しかし理由です。そしてしばしば良いものです。