我很熟悉Django,但我最近注意到存在一个on_delete=models。级联选项与模型。我已经搜索了相同的文档,但我找不到更多的东西:

在Django 1.9中更改: On_delete现在可以用作第二个位置参数(以前它通常只作为关键字参数传递)。它将是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做什么?(我猜如果模型被删除了要做的动作。)

什么是模型。级联做什么?(文档中的提示)

还有什么其他的选择(如果我的猜测是正确的)?

这方面的文档放在哪里?


当前回答

CASCADE也会删除与之相连的对应字段。

其他回答

供您参考,模型中的on_delete参数与它听起来的相反。你把on_delete放在一个模型的外键(FK)上,告诉Django如果你在记录上指向的FK条目被删除了该怎么办。我们商店使用最多的选项是PROTECT、CASCADE和SET_NULL。以下是我总结出的基本规则:

Use PROTECT when your FK is pointing to a look-up table that really shouldn't be changing and that certainly should not cause your table to change. If anyone tries to delete an entry on that look-up table, PROTECT prevents them from deleting it if it is tied to any records. It also prevents Django from deleting your record just because it deleted an entry on a look-up table. This last part is critical. If someone were to delete the gender "Female" from my Gender table, I CERTAINLY would NOT want that to instantly delete any and all people I had in my Person table who had that gender. Use CASCADE when your FK is pointing to a "parent" record. So, if a Person can have many PersonEthnicity entries (he/she can be American Indian, Black, and White), and that Person is deleted, I really would want any "child" PersonEthnicity entries to be deleted. They are irrelevant without the Person. Use SET_NULL when you do want people to be allowed to delete an entry on a look-up table, but you still want to preserve your record. For example, if a Person can have a HighSchool, but it doesn't really matter to me if that high-school goes away on my look-up table, I would say on_delete=SET_NULL. This would leave my Person record out there; it just would just set the high-school FK on my Person to null. Obviously, you will have to allow null=True on that FK.

下面是一个模型的例子,它可以做到这三件事:

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吗?这意味着如果有人删除了您的gender表中的一个性别条目,那么具有该性别的任何Person记录也会被删除!

我会说,“如果有疑问,设置on_delete=models.PROTECT。”然后测试你的应用程序。您将很快发现哪些fk应该标记为其他值,而不会危及任何数据。

此外,值得注意的是,on_delete=CASCADE实际上没有添加到任何迁移中,如果这是您选择的行为的话。我想这是因为它是默认的,所以把on_delete=CASCADE等同于什么都不放。

重新定位你对“CASCADE”功能的思维模式,将FK添加到一个已经存在的CASCADE(即瀑布)中。这个瀑布的源是一个主键(PK)。删除向下流动。

因此,如果您将一个FK的on_delete定义为“CASCADE”,那么您将把这个FK的记录添加到一个源于PK的级联删除中。FK的记录可能参与这个级联,也可能不参与(“SET_NULL”)。事实上,具有FK的记录甚至可能阻止删除流!用“PROTECT”建造一座大坝。

这是删除引用对象时采用的行为。它不是Django特有的;这是一个SQL标准。尽管Django在SQL之上有自己的实现。(1)

当此类事件发生时,可以采取7种措施:

CASCADE: When the referenced object is deleted, also delete the objects that have references to it (when you remove a blog post for instance, you might want to delete comments as well). SQL equivalent: CASCADE. PROTECT: Forbid the deletion of the referenced object. To delete it you will have to delete all objects that reference it manually. SQL equivalent: RESTRICT. RESTRICT: (introduced in Django 3.1) Similar behavior as PROTECT that matches SQL's RESTRICT more accurately. (See django documentation example) SET_NULL: Set the reference to NULL (requires the field to be nullable). For instance, when you delete a User, you might want to keep the comments he posted on blog posts, but say it was posted by an anonymous (or deleted) user. SQL equivalent: SET NULL. SET_DEFAULT: Set the default value. SQL equivalent: SET DEFAULT. SET(...): Set a given value. This one is not part of the SQL standard and is entirely handled by Django. DO_NOTHING: Probably a very bad idea since this would create integrity issues in your database (referencing an object that actually doesn't exist). SQL equivalent: NO ACTION. (2)

来源:Django文档

例如,请参阅PostgreSQL的文档。

在大多数情况下,CASCADE是预期的行为,但对于每个ForeignKey,你应该总是问自己在这种情况下预期的行为是什么。PROTECT和SET_NULL通常很有用。在不应该的地方设置CASCADE,只需删除单个用户,就可以潜在地级联删除所有数据库。


澄清级联方向的附加说明

有趣的是,许多人都不清楚CASCADE动作的方向。实际上,有趣的是,只有CASCADE动作是不清楚的。我知道级联行为可能会让人困惑,但你必须认为它与任何其他行为的方向相同。因此,如果您觉得CASCADE方向不清楚,这实际上意味着on_delete行为不清楚。

In your database, a foreign key is basically represented by an integer field which value is the primary key of the foreign object. Let's say you have an entry comment_A, which has a foreign key to an entry article_B. If you delete the entry comment_A, everything is fine. article_B used to live without comment_A and don't bother if it's deleted. However, if you delete article_B, then comment_A panics! It never lived without article_B and needs it, it's part of its attributes (article=article_B, but what is article_B???). This is where on_delete steps in, to determine how to resolve this integrity error, either by saying:

“不!拜托!不!我不能没有你!”(在Django/SQL中是PROTECT或RESTRICT) “好吧,如果我不是你的,那我就不是任何人的”(SET_NULL) “再见世界,我不能没有article_B”然后自杀(这是CASCADE行为)。 “没关系,我有一个备用情人,我将从现在开始引用article_C”(SET_DEFAULT,甚至SET(…))。 “我无法面对现实,我会一直叫你的名字,即使那是我唯一剩下的东西!”(DO_NOTHING)

我希望它能让瀑布方向更清晰。:)


脚注

Django在SQL之上有自己的实现。并且,正如下面@JoeMjr2在评论中提到的,Django不会创建SQL约束。如果您希望数据库确保约束(例如,如果您的数据库由另一个应用程序使用,或者您不时挂在数据库控制台中),您可能希望自己手动设置相关的约束。在Django中增加对数据库级删除约束的支持是开放的。

(2)实际上,有一种情况下DO_NOTHING是有用的:如果你想跳过Django的实现,自己在数据库级实现约束。

使用CASCADE实际上意味着告诉Django删除引用的记录。 当一个“问题”被删除时,它也会删除这个问题的选项。

问:你是怎么知道我们公司的? (选择:1。朋友2。电视广告搜索引擎4。电子邮件推广)

当您删除这个问题时,它也会从表中删除所有这四个选项。 注意它流动的方向。 你不需要输入on_delete=models。问题级联模型把它放在选择中。

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)

CASCADE也会删除与之相连的对应字段。