这是删除referenced对象时要采用的行为.这不是Django特有的;这是一个SQL标准.尽管Django在SQL之上有自己的实现.(1)
发生此类事件时,可采取七种可能的操作:
CASCADE
:删除被引用的对象时,也要删除对其有引用的对象(例如,当你删除一篇博客文章时,你可能也想删除 comments ).SQL等效值:CASCADE
.
PROTECT
:禁止删除被引用的对象.要删除它,您必须手动删除引用它的所有对象.SQL类似功能:RESTRICT
.
RESTRICT
:(introduced in Django 3.1)与PROTECT
类似的行为,更精确地匹配SQL的RESTRICT
.(见django documentation example)
SET_NULL
:将引用设置为NULL(要求字段可为NULL).例如,当你删除一个用户时,你可能想保留他在博客帖子上发表的 comments ,但说它是由一个匿名(或已删除)用户发布的.SQL类似功能:SET NULL
.
SET_DEFAULT
:设置默认值.SQL类似功能:SET DEFAULT
.
SET(...)
:设置一个给定的值.这不是SQL标准的一部分,完全由Django处理.
DO_NOTHING
:这可能是一个非常糟糕的主意,因为这会在数据库中产生完整性问题(引用实际上不存在的对象).SQL类似功能:NO ACTION
.(2)
资料来源:Django documentation
例如,参见the documentation of PostgreSQL.
在大多数情况下,CASCADE
是预期的行为,但对于每一个 foreign 人,你应该始终问自己在这种情况下预期的行为是什么.PROTECT
和SET_NULL
通常很有用.如果不应该设置CASCADE
,只需删除一个用户,就可以级联删除所有数据库.
Additional note to clarify cascade direction个
有趣的是,注意到CASCADE
行动的方向对许多人来说并不清楚.实际上,有趣的是注意到only和CASCADE
的动作并不清楚.我理解级联行为可能会令人困惑,但是您必须考虑到it is the same direction as any other action.所以,如果你觉得CASCADE
的方向你不清楚,其实就是on_delete
的行为你不清楚.
在您的数据库中,外键基本上由一个整型字段表示,该值是外键的主键.假设您有一个条目comment_A,它具有指向条目article_B的外键.如果删除条目comment_A,则一切正常.article_B过go 没有comment_A也活着,如果被删除了也不用费心了.但是,如果你删掉article_B,那么comment_A就会panic !它从来没有离开过article_B并且需要它,而且它是它的属性的一部分(article=article_B
,但是article_B是什么呢?).这就是on_delete
个步骤,以确定如何解决这个integrity error问题,方法是说:
- "No! Please! Don't! I can't live without you!"(在Django/SQL中表示为
PROTECT
或RESTRICT
)
- "All right, if I'm not yours, then I'm nobody's"(也就是说
SET_NULL
)
- "Good bye world, I can't live without article_B"然后自杀(这是
CASCADE
的行为).
- "It's OK, I've got spare lover, and I'll reference article_C from now"(
SET_DEFAULT
,甚至SET(...)
).
- "I can't face reality, and I'll keep calling your name even if that's the only thing left to me!" (
DO_NOTHING
)
我希望这能让cascade的方向更清晰.:)
Footnotes
(1) Django在SQL之上有自己的实现.而且,作为mentioned by @JoeMjr2 in the comments below,Django将不会创建SQL约束.如果您希望数据库确保约束(例如,如果您的数据库由另一个应用程序使用,或者如果您经常挂起数据库控制台),您可能希望自己手动设置相关的约束.在Django中有an open ticket个要添加对删除约束的数据库级别的支持.
(2)实际上,有一种情况下DO_NOTHING
可能很有用:如果您想跳过Django的实现,自己在数据库级别实现约束.