on_delete在Django模型上做了什么?

时间:2016-07-15 05:26:57

标签: python django django-models

我对Django非常熟悉,但最近注意到模型中存在on_delete=models.CASCADE选项,我搜索了相同的文档,但找不到以下内容:< / p>

  

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

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

此文档的位置在哪里?

11 个答案:

答案 0 :(得分:404)

这是删除引用的对象时要采用的行为。它不是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置于不应该的位置,可以通过简单地删除单个用户来潜在地删除所有数据库。

答案 1 :(得分:31)

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

Here's the entire official documentation.

答案 2 :(得分:24)

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

  1. 当您的FK指向一个确实不应该更改的查找表时,请使用PROTECT,当然不应该导致您的表更改。如果有人试图删除该查找表上的条目,PROTECT会阻止它们删除它,如果它绑定到任何记录。它还会阻止django删除您的记录,因为它删除了查找表中的条目。最后一部分是至关重要的。 如果有人要删除性别&#34;女性&#34;从我的性别表中,我一定不希望它立即删除我在Person表中拥有该性别的所有人。
  2. 当您的FK指向&#34;父母&#34;时使用CASCADE记录。因此,如果一个人可以拥有许多PersonEthnicity条目(他/她可以是美洲印第安人,黑人和白人),并且该人删除,我真的想要任何&#34;子&#34;要删除的PersonEthnicity条目。没有这个人,他们就无关紧要了。
  3. 执行时,请使用SET_NULL希望允许其他人删除查找表中的条目,但您仍希望保留您的记录。例如,如果一个人可以拥有一个HighSchool,但如果我的查找表中的那个高中学校消失对我来说并不重要,我会说&#34; on_delete = SET_NULL。&#34 ;这会留下我的人员记录;它只是将我的Person上的高中FK设置为​​null。显然,你必须在FK上允许null = True。
  4. 这是一个完成所有三件事的模型示例:

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

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

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

答案 3 :(得分:3)

如前所述,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 == 1。但是,如果您创建自定义报告或自定义查询来下拉已删除记录的列表,甚至更多,以便查看上次修改的时间(另一个字段)以及由谁(即谁删除它以及何时删除)。从执行人员的角度来看,这是非常有利的。

请不要忘记,对于这些记录,您可以还原像deleted = 0这样的意外删除。

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

答案 4 :(得分:3)

以下是您的问题的答案:“为什么我们使用on_delete?

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

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

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

CASCADE:级联删除;默认值。

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

SET_NULL::将ForeignKey设置为null;仅当null为True时才可能。

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

答案 5 :(得分:3)

假设您有两种模型,一种名为 Person ,另一种名为 Companies

根据定义,一个人可以创建多个公司。

考虑到一个公司可以只有一个人,我们希望在删除一个人时也删除与该人关联的所有公司。

因此,我们首先创建一个Person模型,就像这样

class Person(models.Model):
    id = models.IntegerField(primary_key=True)
    name = models.CharField(max_length=20)

    def __str__(self):
        return self.id+self.name

然后,“公司”模型如下所示:

class Companies(models.Model):
    title = models.CharField(max_length=20)
    description=models.CharField(max_length=10)
    person= models.ForeignKey(Person,related_name='persons',on_delete=models.CASCADE)

请注意在公司模型中使用on_delete=models.CASCADE。那就是删除拥有它的人(Person类的实例)时删除所有公司。

答案 6 :(得分:2)

使用 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)

答案 7 :(得分:1)

通过考虑将FK添加到已存在的级联(即瀑布)中来重新定位“ CASCADE”功能的思维模型。该瀑布的来源是主键(PK)。删除流向下。

因此,如果将FK的on_delete定义为“ CASCADE”,则需要将此FK的记录添加到源自PK的一系列删除中。 FK的记录是否可以参与此级联(“ SET_NULL”)。实际上,带有FK的记录甚至可能阻止删除流程!用“保护”建造大坝。

答案 8 :(得分:0)

django==1.11.22具有以下代码。这意味着on_delete会偏离CASCADE

class ForeignKey(ForeignObject):
    .......
        if on_delete is None:
            warnings.warn(
                "on_delete will be a required arg for %s in Django 2.0. Set "
                "it to models.CASCADE on models and in existing migrations "
                "if you want to maintain the current default behavior. "
                "See https://docs.djangoproject.com/en/%s/ref/models/fields/"
                "#django.db.models.ForeignKey.on_delete" % (
                    self.__class__.__name__,
                    get_docs_version(),
                ),
                RemovedInDjango20Warning, 2)
            on_delete = CASCADE
    .......

答案 9 :(得分:0)

CASCADE还将删除与其关联的相应字段。

答案 10 :(得分:0)

删除数据库中的所有字段,然后我们使用on_delete

class user(models.Model):
 commodities = models.ForeignKey(commodity, on_delete=models.CASCADE)