Python on_delete 对 Django 模型有什么作用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38388423/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 20:43:12  来源:igfitidea点击:

what does on_delete do on Django models?

pythondjangodjango-models

提问by All ?? Vаи?тy

I'm quite familiar with Django, but recently noticed there exists an on_delete=models.CASCADEoption with the models, I have searched for the documentation for the same but couldn't find anything more than:

我对 Django 非常熟悉,但最近注意到on_delete=models.CASCADE模型中有一个选项,我已经搜索了相同的文档,但除了以下内容之外找不到任何其他内容:

Changed in Django 1.9:

on_deletecan 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.

在 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

What does on_delete do? (I guess the actions to be done if the model is deleted)

on_delete 有什么作用?(我猜如果删除模型要执行的操作

What does models.CASCADEdo? (any hints in documentation)

有什么作用models.CASCADE?(文档中的任何提示

What other options are available (if my guess is correct)?

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

Where does the documentation for this reside?

这方面的文档在哪里?

回答by Antoine Pinsard

This is the behaviour to adopt when the referencedobject is deleted. It is not specific to django, this is an SQL standard.

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

There are 6 possible actions to take when such event occurs:

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

  • 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.
  • 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.

Source: Django documentation

来源:Django 文档

See also the documentation of PostGreSQLfor instance.

例如,另请参阅PostGreSQL 的文档

In most cases, CASCADEis the expected behaviour, but for every ForeignKey, you should always ask yourself what is the expected behaviour in this situation. PROTECTand SET_NULLare often useful. Setting CASCADEwhere it should not, can potentially delete all your database in cascade, by simply deleting a single user.

在大多数情况下,CASCADE是预期的行为,但对于每个外键,您应该始终问自己在这种情况下的预期行为是什么。PROTECT并且SET_NULL经常有用。设置CASCADE不该设置的地方,可能会通过简单地删除单个用户来潜在地级联删除所有数据库。



Additional note to clarify cascade direction

澄清级联方向的附加说明

It's funny to notice that the direction of the CASCADEaction is not clear to many people. Actually, it's funny to notice that onlythe CASCADEaction 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 CASCADEdirection is not clear to you, it actually means that on_deletebehavior is not clear to you.

有趣的CASCADE是,很多人都不清楚行动的方向。事实上,这很有趣地看到,只有CASCADE行动并不清楚。我知道级联行为可能会令人困惑,但是您必须认为它与任何其他操作的方向相同。因此,如果你觉得CASCADE方向对你来说不清楚,那实际上意味着on_delete行为对你来说并不明确。

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_Bused to live without comment_Aand don't bother if it's deleted. However, if you delete article_B, then comment_Apanics! It never lived without article_Band needs it, it's part of its attributes (article=article_B, but what is *article_B**???). This is where on_deletesteps in, to determine how to resolve this integrity error, either by saying:

在您的数据库中,外键基本上由一个整数字段表示,该字段的值是外对象的主键。假设您有一个条目comment_A,它有一个条目article_B的外键。如果您删除条目comment_A,则一切正常,article_B过去没有comment_A也可以生存,如果删除了也不要打扰。但是,如果您删除article_B,则comment_A 会发生恐慌!它从来没有没有article_B并且需要它,这是它的属性的一部分(article=article_B但什么是 *article_B**???)。这是on_delete介入的地方,以确定如何解决此完整性错误,或者说:

  • "No! Please! Don't! I can't live without you!"(which is said PROTECTin 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 CASCADEbehavior).
  • "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)
  • “不!求求你!不要!没有你我​​活不下去!” (这是PROTECT用SQL语言说的)
  • “好吧,如果我不是你的,那么我就是别人的”(据说SET_NULL
  • “再见世界,我不能没有文章_B”并自杀(这是CASCADE行为)。
  • “没关系,我有空余情人,我从现在开始参考文章_C”SET_DEFAULT,甚至SET(...))。
  • “我无法面对现实,我会一直呼唤你的名字,即使这是我唯一的事!” ( DO_NOTHING)

I hope it makes cascade direction clearer. :)

我希望它使级联方向更清晰。:)

回答by him229

The on_deletemethod is used to tell Django what to do with model instances that depend on the model instance you delete. (e.g. a ForeignKeyrelationship). The on_delete=models.CASCADEtells Django to cascade the deleting effect i.e. continue deleting the dependent models as well.

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

Here's a more concrete example. Assume you have an Authormodel that is a ForeignKeyin a Bookmodel. Now, if you delete an instance of the Authormodel, Django would not know what to do with instances of the Bookmodel that depend on that instance of Authormodel. The on_deletemethod tells Django what to do in that case. Setting on_delete=models.CASCADEwill instruct Django to cascade the deleting effect i.e. delete all the Bookmodel instances that depend on the Authormodel instance you deleted.

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

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

注意:on_delete将成为 Django 2.0 中的必需参数。在旧版本中,它默认为CASCADE.

Here's the entire official documentation.

这是整个官方文档。

回答by HelenM

FYI, the on_deleteparameter in models is backwards from what it sounds like. You put on_deleteon 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:

仅供参考,on_delete模型中的参数与听起来相反。您on_delete在模型上放置外键 (FK) 以告诉 django 如果您在记录中指向的 FK 条目被删除该怎么办。选项我们店已经使用的大多是PROTECTCASCADESET_NULL。以下是我想出的基本规则:

  1. Use PROTECTwhen your FK is pointing to a look-up table that really shouldn't be changing and that certainlyshould not cause your table to change. If anyone tries to delete an entry on that look-up table, PROTECTprevents them from deleting it if it is tied to any records. It also prevents django from deleting yourrecord 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.
  2. Use CASCADEwhen 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 isdeleted, I really wouldwant any "child" PersonEthnicity entries to be deleted. They are irrelevant without the Person.
  3. Use SET_NULLwhen you dowant 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=Trueon that FK.
  1. 使用PROTECT时,你的FK指向一个查表真的不应该被改变,并且肯定不会引起你的表来改变。如果有人试图删除该查找表上的条目,如果该条目PROTECT与任何记录相关联,则阻止他们删除该条目。它还可以防止 django 删除您的记录,因为它删除了查找表中的条目。这最后一部分至关重要。 如果有人要从我的 Gender 表中删除性别“Female”,我当然不希望它立即删除我的 Person 表中具有该性别的任何和所有人。
  2. 使用CASCADE时,你的FK指向“父”的纪录。所以,如果一个人可以有很多PersonEthnicity项(他/她可以是美洲印第安人,黑色和白色),而那个人删除了,我真的想什么“孩子” PersonEthnicity条目被删除。如果没有人,它们就无关紧要。
  3. 使用SET_NULL时,你希望人们被允许删除查找表中的条目,但你仍然要保留记录。例如,如果一个人可以拥有 HighSchool,但那所高中是否在我的查找表上消失对我来说并不重要,我会说on_delete=SET_NULL. 这会留下我的 Person 记录;它只会将我的 Person 上的高中 FK 设置为空。显然,您将null=True不得不允许该 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'tspecify 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!

作为最后的花絮,您是否知道如果您指定on_delete(或没有指定),默认行为是CASCADE?这意味着如果有人删除了您的 Gender 表中的性别条目,则该性别的任何 Person 记录也将被删除!

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.

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

Also, it is worth noting that on_delete=CASCADEis 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=CASCADEis the same thing as putting nothing.

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

回答by George Mogilevsky

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

如前所述,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

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.

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

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.

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

And don't forget that you can revert accidental deletions as simple as deleted = 0for those records.

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

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.

我的观点是,如果有一个功能,它背后总有一个原因。并不总是一个很好的理由。而是一个原因。而且通常也是不错的。

回答by Sonia Rani

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

这是您的问题的答案:为什么我们使用 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:

当 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)

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

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

CASCADE:Cascade deletes; the default.

CASCADE:级联删除;默认值。

PROTECT:Prevent deletion of the referenced object by raising ProtectedError, a subclass of django.db.IntegrityError.

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

SET_NULL:Set the ForeignKey null; this is only possible if null is True.

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

SET_DEFAULT:Set the ForeignKey to its default value; a default for the ForeignKey must be set.

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

回答by u5675325

Let's say you have two models, one named Personand another one named Companies.

假设您有两个模型,一个名为Person,另一个名为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

所以,我们首先创建一个 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

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.CASCADEin the model Companies. That is to delete all companies when the person that owns it (instance of class Person) is deleted.

注意on_delete=models.CASCADE在模型 Companies 中的用法。即当拥有它的人(Person 类的实例)被删除时,删除所有公司。

回答by gregory

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.

通过考虑向已经存在的级联(即瀑布)添加 FK,重新定位“CASCADE”功能的心智模型。这个瀑布的来源是一个主键。删除流向下。

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."

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

回答by Kunal

Using CASCADEmeans 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.

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

e.g Question: How did you hear about us? (Choices: 1. Friends 2. TV Ad 3. Search Engine 4. Email Promotion)

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

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.

当您删除此问题时,它也会从表中删除所有这四个选项。注意它流向哪个方向。您不必在问题模型中放入 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)