这是删除引用对象时采用的行为。它不是Django特有的;这是一个SQL标准。尽管Django在SQL之上有自己的实现。(1)
当此类事件发生时,可以采取7种措施:
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.
RESTRICT: (introduced in Django 3.1) Similar behavior as PROTECT that matches SQL's RESTRICT more accurately. (See django documentation example)
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. (2)
来源:Django文档
例如,请参阅PostgreSQL的文档。
在大多数情况下,CASCADE是预期的行为,但对于每个ForeignKey,你应该总是问自己在这种情况下预期的行为是什么。PROTECT和SET_NULL通常很有用。在不应该的地方设置CASCADE,只需删除单个用户,就可以潜在地级联删除所有数据库。
澄清级联方向的附加说明
有趣的是,许多人都不清楚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_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:
“不!拜托!不!我不能没有你!”(在Django/SQL中是PROTECT或RESTRICT)
“好吧,如果我不是你的,那我就不是任何人的”(SET_NULL)
“再见世界,我不能没有article_B”然后自杀(这是CASCADE行为)。
“没关系,我有一个备用情人,我将从现在开始引用article_C”(SET_DEFAULT,甚至SET(…))。
“我无法面对现实,我会一直叫你的名字,即使那是我唯一剩下的东西!”(DO_NOTHING)
我希望它能让瀑布方向更清晰。:)
脚注
Django在SQL之上有自己的实现。并且,正如下面@JoeMjr2在评论中提到的,Django不会创建SQL约束。如果您希望数据库确保约束(例如,如果您的数据库由另一个应用程序使用,或者您不时挂在数据库控制台中),您可能希望自己手动设置相关的约束。在Django中增加对数据库级删除约束的支持是开放的。
(2)实际上,有一种情况下DO_NOTHING是有用的:如果你想跳过Django的实现,自己在数据库级实现约束。