问题: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
办?(文档中的任何提示)
还有其他可用的选项(如果我的猜测是正确的)?
有关此文档的位置在哪里?
I’m quite familiar with Django, but recently noticed there exists an on_delete=models.CASCADE
option with the models, I have searched for the documentation for the same but couldn’t find anything more than:
Changed in Django 1.9:
on_delete
can now be used as the second positional argument (previously it was typically only passed as a keyword argument). It will be a required argument in 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
What does on_delete do? (I guess the actions to be done if the model is deleted)
What does models.CASCADE
do? (any hints in documentation)
What other options are available (if my guess is correct)?
Where does the documentation for this reside?
回答 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
)
我希望它使级联方向更清晰。:)
This is the behaviour to adopt when the referenced object is deleted. It is not specific to django, this is an SQL standard.
There are 6 possible actions to take when such event occurs:
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
.
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
.
Source: Django documentation
See also the documentation of PostGreSQL for instance.
In most cases, CASCADE
is the expected behaviour, but for every ForeignKey, you should always ask yourself what is the expected behaviour in this situation. PROTECT
and SET_NULL
are often useful. Setting CASCADE
where it should not, can potentially delete all your database in cascade, by simply deleting a single user.
Additional note to clarify cascade direction
It’s funny to notice that the direction of the CASCADE
action is not clear to many people. Actually, it’s funny to notice that only the CASCADE
action is not clear. I understand the cascade behavior might be confusing, however you must think that it is the same direction as any other action. Thus, if you feel that CASCADE
direction is not clear to you, it actually means that on_delete
behavior is not clear to you.
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:
- “No! Please! Don’t! I can’t live without you!” (which is said
PROTECT
in SQL language)
- “Alright, if I’m not yours, then I’m nobody’s” (which is said
SET_NULL
)
- “Good bye world, I can’t live without article_B” and commit suicide (this is the
CASCADE
behavior).
- “It’s OK, I’ve got spare lover, I’ll reference article_C from now” (
SET_DEFAULT
, or even SET(...)
).
- “I can’t face reality, I’ll keep calling your name even if that’s the only thing left to me!” (
DO_NOTHING
)
I hope it makes cascade direction clearer. :)
回答 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
。
这是完整的官方文档。
The on_delete
method is used to tell Django what to do with model instances that depend on the model instance you delete. (e.g. a ForeignKey
relationship). The on_delete=models.CASCADE
tells Django to cascade the deleting effect i.e. continue deleting the dependent models as well.
Here’s a more concrete example. Assume you have an Author
model that is a ForeignKey
in a Book
model. Now, if you delete an instance of the Author
model, Django would not know what to do with instances of the Book
model that depend on that instance of Author
model. The on_delete
method tells Django what to do in that case. Setting on_delete=models.CASCADE
will instruct Django to cascade the deleting effect i.e. delete all the Book
model instances that depend on the Author
model instance you deleted.
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.
回答 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
和放置任何东西都是一样的。
FYI, the on_delete
parameter in models is backwards from what it sounds like. You put on_delete
on a Foreign Key (FK) on a model to tell django what to do if the FK entry that you are pointing to on your record is deleted. The options our shop have used the most are PROTECT
, CASCADE
, and SET_NULL
. Here are the basic rules I have figured out:
- 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.
Here is an example of a model that does all three things:
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'
As a last tidbit, did you know that if you don’t specify on_delete
(or didn’t), the default behavior is CASCADE
? This means that if someone deleted a gender entry on your Gender table, any Person records with that gender were also deleted!
I would say, “If in doubt, set on_delete=models.PROTECT
.” Then go test your application. You will quickly figure out which FKs should be labeled the other values without endangering any of your data.
Also, it is worth noting that on_delete=CASCADE
is actually not added to any of your migrations, if that is the behavior you are selecting. I guess this is because it is the default, so putting on_delete=CASCADE
is the same thing as putting nothing.
回答 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
那些记录一样简单地还原意外删除。
我的观点是,如果有功能,总会有其背后的原因。并非总是一个很好的理由。但这是一个原因。往往也是一个好人。
As mentioned earlier, CASCADE will delete the record that has a foreign key and references another object that was deleted. So for example if you have a real estate website and have a Property that references a City
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
and now when the City is deleted from the database, all associated Properties (eg. real estate located in that city) will also be deleted from the database
Now I also want to mention the merit of other options, such as SET_NULL or SET_DEFAULT or even DO_NOTHING. Basically, from the administration perspective, you want to “delete” those records. But you don’t really want them to disappear. For many reasons. Someone might have deleted it accidentally, or for auditing and monitoring. And plain reporting. So it can be a way to “disconnect” the property from a City. Again, it will depend on how your application is written.
For example, some applications have a field “deleted” which is 0 or 1. And all their searches and list views etc, anything that can appear in reports or anywhere the user can access it from the front end, exclude anything that is deleted == 1
. However, if you create a custom report or a custom query to pull down a list of records that were deleted and even more so to see when it was last modified (another field) and by whom (i.e. who deleted it and when)..that is very advantageous from the executive standpoint.
And don’t forget that you can revert accidental deletions as simple as deleted = 0
for those records.
My point is, if there is a functionality, there is always a reason behind it. Not always a good reason. But a reason. And often a good one too.
回答 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设置默认值。
Here is answer for your question that says: why we use on_delete?
When an object referenced by a ForeignKey is deleted, Django by default emulates the behavior of the SQL constraint ON DELETE CASCADE and also deletes the object containing the ForeignKey. This behavior can be overridden by specifying the on_delete argument. For example, if you have a nullable ForeignKey and you want it to be set null when the referenced object is deleted:
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: Cascade deletes; the default.
PROTECT: Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.
SET_NULL: Set the ForeignKey null; this is only possible if null is True.
SET_DEFAULT: Set the ForeignKey to its default value; a default for the ForeignKey must be set.
回答 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类的实例)时删除所有公司。
Let’s say you have two models, one named Person and another one named Companies.
By definition, one person can create more than one company.
Considering a company can have one and only one person, we want that when a person is deleted that all the companies associated with that person also be deleted.
So, we start by creating a Person model, like this
class Person(models.Model):
id = models.IntegerField(primary_key=True)
name = models.CharField(max_length=20)
def __str__(self):
return self.id+self.name
Then, the Companies model can look like this
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)
Notice the usage of on_delete=models.CASCADE
in the model Companies. That is to delete all companies when the person that owns it (instance of class Person) is deleted.
回答 6
通过考虑将FK添加到已存在的级联(即瀑布)中来重新定向“ CASCADE”功能的思维模型。该瀑布的来源是主键。删除流向下。
因此,如果将FK的on_delete定义为“ CASCADE”,则需要将此FK的记录添加到源自PK的一系列删除中。FK的记录是否可以参与此级联(“ SET_NULL”)。实际上,带有FK的记录甚至可能阻止删除流程!用“保护”建造一个水坝。
Re-orient your mental model of the functionality of “CASCADE” by thinking of adding a FK to an already existing cascade (i.e. a waterfall). The source of this waterfall is a Primary Key. Deletes flow down.
So if you define a FK’s on_delete as “CASCADE,” you’re adding this FK’s record to a cascade of deletes originating from the PK. The FK’s record may participate in this cascade or not (“SET_NULL”). In fact, a record with a FK may even prevent the flow of the deletes! Build a dam with “PROTECT.”
回答 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)
Using CASCADE means actually telling Django to delete the referenced record.
In the poll app example below: When a ‘Question’ gets deleted it will also delete the Choices this Question has.
e.g Question: How did you hear about us?
(Choices: 1. Friends 2. TV Ad 3. Search Engine 4. Email Promotion)
When you delete this question, it will also delete all these four choices from the table.
Note that which direction it flows.
You don’t have to put on_delete=models.CASCADE in Question Model put it in the 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)