问题:on_delete对Django模型有什么作用?
我对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
on_delete是做什么的?(我想如果删除模型,要执行的操作)
怎么models.CASCADE
办?(文档中的任何提示)
还有其他可用的选项(如果我的猜测是正确的)?
有关此文档的位置在哪里?
回答 0
这是删除引用对象时采取的行为。它不是特定于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
不应该设置的位置,可以通过简单地删除单个用户来级联删除所有数据库。
附加说明以阐明级联方向
有趣的是,注意到CASCADE
行动的方向对于许多人来说并不明确。事实上,这很有趣地看到,只有该CASCADE
行动并不清楚。我知道级联行为可能会造成混淆,但是您必须认为它与任何其他动作是同一方向。因此,如果您觉得自己CASCADE
不清楚方向,那实际上意味着on_delete
您不清楚自己的行为。
在您的数据库中,外键基本上由一个整数字段表示,该字段的值是外对象的主键。假设您有一个comment_A条目,它具有一个article_B条目的外键。如果您删除条目comment_A,那么一切都很好,article_B以前可以不带有comment_A生存,并且也不会被删除。但是,如果删除article_B,则comment_A会慌!它永远都离不开article_B并需要它,它是它属性的一部分(article=article_B
,但是* article_B ** ???)。这是on_delete
确定如何解决此完整性错误的步骤,或者说:
- “不!请!不要!我不能没有你!” (
PROTECT
用SQL语言表示) - “好吧,如果我不是你的,那我就不是任何人的”(说
SET_NULL
) - “再见,我不能没有article_B生活”自杀(这是
CASCADE
行为)。 - “没关系,我有多余的恋人,从现在开始我将引用article_C”(
SET_DEFAULT
,甚至SET(...)
)。 - “我不能面对现实,即使那是我唯一的事情,我也会继续给你起名字!” (
DO_NOTHING
)
我希望它使级联方向更清晰。:)
回答 1
该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
。
回答 2
仅供参考,on_delete
模型中的参数从听起来像是倒过来的。您on_delete
在模型上放置了外键(FK),以告诉django如果删除了记录中指向的FK条目该怎么办。选项我们店已经使用的大多是PROTECT
,CASCADE
和SET_NULL
。这是我弄清楚的基本规则:
- 使用
PROTECT
时,你的FK指向一个查表真的不应该被改变,并且肯定不会引起你的表来改变。如果有人试图删除该查询表上的条目,则PROTECT
防止该条目与任何记录绑定时删除该条目。它还可以防止从删除的Django 你的记录,只是因为它删除了一个查找表中的条目。最后一部分至关重要。 如果有人要从“性别”表中删除性别“女性”,我肯定不希望立即删除我在“人”表中拥有该性别的任何人。 - 使用
CASCADE
时,你的FK指向“父”的纪录。所以,如果一个人可以有很多PersonEthnicity项(他/她可以是美洲印第安人,黑色和白色),而那个人被删除了,我真的会想什么“孩子” PersonEthnicity条目被删除。没有人,他们是无关紧要的。 - 使用
SET_NULL
时,你也希望人们被允许删除查找表中的条目,但你仍然要保留记录。例如,如果某人可以拥有一所高中,但对我而言,那所高中不在我的查询表上并不重要on_delete=SET_NULL
。这会将我的“个人”记录保留在那里;只会将“我的人”上的高中FK设置为null。显然,您必须允许null=True
该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
?这意味着,如果有人删除了您“性别”表上的性别条目,则具有该性别的任何“人”记录也将被删除!
我会说:“如果有疑问,那就出发on_delete=models.PROTECT
。” 然后测试您的应用程序。您将快速找出哪些FK应该标记为其他值,而不会危及您的任何数据。
另外,值得注意的on_delete=CASCADE
是,如果这是您选择的行为,实际上并没有添加到您的任何迁移中。我猜这是因为它是默认设置,所以放置on_delete=CASCADE
和放置任何东西都是一样的。
回答 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
这是您的问题答案:为什么我们使用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)
on_delete的可能值在django.db.models中找到:
级联:级联删除;默认值。
保护:通过引发ProtectedError(django.db.IntegrityError的子类)来防止删除引用的对象。
SET_NULL:将ForeignKey设置为null;否则为false。仅当null为True时才有可能。
SET_DEFAULT:将ForeignKey设置为其默认值;必须为ForeignKey设置默认值。
回答 5
假设您有两种模型,一种名为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
通过考虑将FK添加到已存在的级联(即瀑布)中来重新定向“ CASCADE”功能的思维模型。该瀑布的来源是主键。删除流向下。
因此,如果将FK的on_delete定义为“ CASCADE”,则需要将此FK的记录添加到源自PK的一系列删除中。FK的记录是否可以参与此级联(“ SET_NULL”)。实际上,带有FK的记录甚至可能阻止删除流程!用“保护”建造一个水坝。
回答 7
使用CASCADE意味着实际上告诉Django删除引用的记录。在下面的民意调查应用示例中:当“问题”被删除时,它还将删除该问题具有的选择。
例如:问题:您如何得知我们的?(选择:1.朋友2.电视广告3.搜索引擎4.电子邮件促销)
删除此问题时,它还将从表中删除所有这四个选项。 请注意它流动的方向。您不必放置on_delete = models。问题模型中的CASCADE将其放置在Choice中。
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)