on_delete在Django模型上做了什么?

Mar*_*rty 261 python django django-models

我对Django很熟悉,但最近注意到on_delete=models.CASCADE模型中存在一个选项,我搜索了相同的文档,但找不到更多:

在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
Run Code Online (Sandbox Code Playgroud)

on_delete做什么?(我想如果删除模型需要完成的操作)

怎么models.CASCADE办?(文档中的任何提示)

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

这个文档在哪里?

Ant*_*ard 546

这是删除引用对象时要采用的行为.它不是django特有的,这是一个SQL标准.

发生此类事件时,可能会采取以下6种操作:

  • CASCADE:删除引用的对象时,也删除引用它的对象(例如,当您删除博客文章时,您可能也想删除注释).SQL等价物:CASCADE.
  • PROTECT:禁止删除引用的对象.要删除它,您必须删除手动引用它的所有对象.SQL等价物:RESTRICT.
  • SET_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不应该的位置,可以通过简单地删除单个用户来潜在地删除所有数据库.

  • @AnthonyManningFranklin当然.仅在引用"已损坏"时触发删除.删除注释时不是这种情况,因为您在同一时间删除了引用. (18认同)
  • 一个愚蠢的问题,但级联应始终是一个方向的权利?即如果`Comment`有一个"BlogPost"的外键,那么删除BlogPost应该删除Comment,但删除Comment不应该删除BlogPost,而不管RDMS? (16认同)
  • 问题不是愚蠢的; 我也需要那个解释.所以在这里我们假设关系是单向的,关系的所有者是`Comment`,在其表中有FK字段,而`BlogPost`"拥有"`Comment`s如果我们谈论现实生活模型.好. (6认同)
  • 需要注意的重要一点是,在 Django 中设置 on_delete 不会在数据库本身中创建 ON DELETE 子句。指定的行为(例如 CASCADE)只会影响通过 Django 执行的删除,而不影响直接在数据库中执行的原始删除。 (6认同)
  • 最后的那些引言看起来像是直接从罗伊·利希滕斯坦的漫画书中摘录的!惊人的 (5认同)
  • 尝试成为一个充满 SET_DEFAULT 的世界中的保护者。 (4认同)
  • 很棒的答案!stackoverflow 上有最佳答案投票吗?:) (4认同)
  • 恭喜你考虑到数据库记录是有感觉的。他们不应该受到虐待。 (2认同)

him*_*229 37

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.

这是完整的官方文档.


Hel*_*enM 31

仅供参考,模型中的on_delete参数是从它听起来的倒退.您将"on_delete"放在模型上的外键(FK)上,告诉django如果删除了您在记录中指向的FK条目该怎么做.我们商店最常用的选项是PROTECT,CASCADE和SET_NULL.以下是我发现的基本规则:

  1. 当你的FK指向一个真正不应该改变的查找表时,请使用PROTECT,这肯定不会导致你的表发生变化.如果有人试图删除该查找表上的条目,PROTECT会阻止它们删除它,如果它绑定到任何记录.它还会阻止django删除您的记录,因为它删除了查找表中的条目.最后一部分是至关重要的. 如果有人要从我的性别表中删除性别"女性",我绝对不会希望立即删除我在Person表中拥有该性别的所有人.
  2. 当您的FK指向"父"记录时,请使用CASCADE.所以,如果一个人可以有很多PersonEthnicity项(他/她可以是美洲印第安人,黑色和白色),而那个人删除了,我真的想删除任何"子" PersonEthnicity条目.没有这个人,他们就无关紧要了.
  3. 使用SET_NULL当你希望人们被允许删除查找表中的条目,但你仍然要保留记录.例如,如果一个人可以拥有一个HighSchool,但如果我的查找表中的那个高中毕业,那对我来说并不重要,我会说"on_delete = SET_NULL".这会留下我的人员记录; 它只是将我的Person上的高中FK设置为​​null.显然,你必须在FK上允许null = True.

以下是完成所有三件事的模型示例:

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'
Run Code Online (Sandbox Code Playgroud)

作为最后一个消息,你知道如果你没有指定on_delete(或没有),默认行为是CASCADE吗?这意味着如果有人在您的性别表上删除了性别条目,则任何具有该性别的人员记录也会被删除!

我会说,"如果有疑问,请设置on_delete = models.PROTECT." 然后去测试你的应用程序.您将很快找出哪些FK应该标记其他值而不会危及您的任何数据.

此外,值得注意的是,on_delete = CASCADE实际上并未添加到任何迁移中,如果这是您选择的行为.我想这是因为它是默认值,所以把on_delete = CASCADE与什么都不做是一回事.


小智 14

简单来说,on_delete 是一条指令,指定在删除外来对象的情况下将对对象进行哪些修改:

CASCADE:当删除外来对象时,将删除子对象

SET_NULL:将子对象外键设置为 null

SET_DEFAULT:将子对象设置为创建模型时给定的默认数据

RESTRICT :RestrictedError 在某些条件下引发 a 。

PROTECT:只要有子对象继承自外来对象,就可以防止外来对象被删除

附加链接:

https://docs.djangoproject.com/en/4.0/ref/models/fields/#foreignkey


小智 7

如前所述,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
Run Code Online (Sandbox Code Playgroud)

现在,当从数据库中删除城市时,所有关联的属性(例如位于该城市的房地产)也将从数据库中删除

现在,我还要提及其他选项的优点,例如SET_NULL或SET_DEFAULT甚至DO_NOTHING。基本上,从管理角度来看,您要“删除”这些记录。但是您真的不希望它们消失。出于很多原因。可能有人不小心删除了该文件,或者进行了审核和监视。和简单的报告。因此,这可能是一种将财产与城市“断开连接”的方式。同样,这将取决于您的应用程序的编写方式。

例如,某些应用程序的“已删除”字段为0或1。所有搜索和列表视图等内容,可能出现在报表中或用户可以从前端访问它的任何位置,均不包括deleted == 1。但是,如果您创建自定义报告或自定义查询来下拉已删除记录的列表,甚至更多,以便查看上次修改的时间(另一个字段)以及由谁(即谁删除它以及何时删除)。从行政角度来看,这是非常有利的。

并且不要忘记,您可以像还原deleted = 0那些记录一样简单地还原意外删除。

我的观点是,如果有功能,总会有其背后的原因。并非总是一个很好的理由。但这是一个原因。往往也是一个好人。

  • 这很有帮助,因为它阐明了CASCADE发生的方向。如果您不熟悉SQL级联,则可接受的答案尚不清楚。 (2认同)
  • 我赞成这个答案,因为它回应了我对关系模型方向的怀疑 (2认同)

小智 7

这是您的问题的答案:为什么我们使用 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)
Run Code Online (Sandbox Code Playgroud)

on_delete 的可能值可以在 django.db.models 中找到:

CASCADE:级联删除;默认值。

PROTECT:通过引发 ProtectedError(django.db.IntegrityError 的子类)来防止删除引用的对象。

SET_NULL:设置外键为空;这只有在 null 为 True 时才有可能。

SET_DEFAULT:将 ForeignKey 设置为其默认值;必须设置 ForeignKey 的默认值。


Kun*_*nal 7

使用CASCADE意味着实际上告诉 Django 删除引用的记录。在下面的投票应用程序示例中:当“问题”被删除时,它也会删除此问题的选项。

例如 问题:您是如何得知我们的?(选择:1. 朋友 2. 电视广告 3. 搜索引擎 4. 电子邮件推广)

当您删除此问题时,它也会从表中删除所有这四个选项。 注意它流向哪个方向。您不必在问题模型中放入 on_delete=models.CASCADE 将其放入选择中。

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)
Run Code Online (Sandbox Code Playgroud)