首页 文章

on_delete在Django模型上做了什么?

提问于
浏览
152

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

在Django 1.9中更改:on_delete现在可以用作第二个位置参数(以前它通常只作为关键字参数传递) . 它将是Django 2.0中的必需参数 .

an example case of usage is

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 做什么? (文档中的任何提示)

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

这个文档在哪里?

5 回答

  • 1

    这是删除引用对象时要采用的行为 . 它不是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 documentation

    例如,参见the documentation of PostGreSQL .

    在大多数情况下, CASCADE 是预期的行为,但是对于每个ForeignKey,您应该总是问自己在这种情况下的预期行为是什么 . PROTECTSET_NULL 通常很有用 . 将 CASCADE 设置为不应该,可以通过简单地删除单个用户来潜在地删除所有数据库 .

  • 288

    on_delete 方法用于告诉Django如何处理依赖于您删除的模型实例的模型实例 . (例如 ForeignKey 关系) . on_delete=models.CASCADE 告诉Django级联删除效果,即继续删除依赖模型 .

    这是一个更具体的例子 . 假设_846259_模型中的 Author 模型是 ForeignKey . 现在,如果删除 Author 模型的实例,Django将不知道如何处理依赖于 Author 模型实例的 Book 模型的实例 . on_delete 方法告诉Django在这种情况下该怎么做 . 设置 on_delete=models.CASCADE 将指示Django级联删除效果,即删除依赖于您删除的 Author 模型实例的所有 Book 模型实例 .

    Note: on_delete will become a required argument in Django 2.0. In older versions it defaults to CASCADE.

    Here's the entire official documentation.

  • 18

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

    • 当你的FK指向一个真正不应该改变的查找表时,请使用PROTECT,这肯定不会导致你的表发生变化 . 如果有人试图删除该查找表上的条目,PROTECT会阻止它们删除它,如果它与任何记录绑定 . 它还可以防止django删除您的记录,因为它删除了查找表中的条目 . 最后一部分至关重要 . 如果有人要从我的性别表中删除性别"Female",我绝不希望立即删除我在Person表中拥有该性别的所有人 .

    • 当FK指向"parent"记录时使用CASCADE . 因此,如果一个人可以拥有许多PersonEthnicity条目(他/她可以是美洲印第安人,黑人和白人),并且该人被删除,我真的希望删除任何"child" PersonEthnicity条目 . 没有这个人,他们是无关紧要的 .

    • 如果您希望允许人们删除查找表中的条目,但仍希望保留您的记录,请使用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'
    

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

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

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

  • 28

    如前所述,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 . 基本上,从管理角度来看,您希望“删除”这些记录 . 但你真的不希望它们消失 . 因为许多的原因 . 有人可能会意外删除它,或者用于审计和监视 . 而且报道很简单 . 因此,它可以是一种将房产与城市“断开”的方式 . 同样,它将取决于您的应用程序的编写方式 .

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

    并且不要忘记,对于那些记录,您可以像 deleted = 0 一样简单地恢复意外删除 .

    我的观点是,如果有功能,总有一个原因 . 并不总是一个很好的理由 . 但原因 . 而且往往也是一个好人 .

  • 1

    Here is answer for your question that says: why we use on_delete?

    删除ForeignKey引用的对象时,Django默认模拟SQL约束ON DELETE CASCADE的行为,并删除包含ForeignKey的对象 . 可以通过指定on_delete参数来覆盖此行为 . 例如,如果您有一个可为空的ForeignKey,并且希望在删除引用的对象时将其设置为null:

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

    The possible values for on_delete are found in django.db.models:

    CASCADE: 级联删除;默认 .

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

    SET_NULL: 设置ForeignKey为null;这只有在null为True时才有可能 .

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

相关问题