Django外键on_delete与db_constraint详解:避免级联删除陷阱
本文详解Django数据模型中外键on_delete参数的行为,重点解析SET_NULL与CASCADE的区别。通过示例说明如何结合null=True、blank=True及db_constraint=False实现断关联但保留查询功能,并介绍ManyToManyField中through参数的应用,帮助开发者避免误删数据及配置错误。
Django外键配置常见问题
在开发过程中,有时会遇到删除某张表记录时,关联的其他表数据也被意外删除的情况。即使设置了db_constraint=False,如果未正确配置on_delete参数,仍可能出现级联删除。例如,将on_delete设为默认的CASCADE会导致关联数据被删。此外,环境配置中若遗漏corsheaders.middleware.CorsMiddleware,可能导致Ajax请求失败。这些细节往往耗费大量调试时间。
on_delete参数详解
1. 设置为null
外键示例:BookModel
class BookModel(models.Model):
"""
图书
"""
book_name = models.CharField(max_length=100, verbose_name='书名')
# 表示外键关联到作者表,当作者表删除了该条数据,图书表中不删除,仅仅是把外键置空
author = models.ForeignKey(AuthModel, null=True, blank=True, on_delete=models.SET_NULL)
price = models.FloatField(verbose_name='价格')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
建表参数设置
2. 建表时其他参数的设置
CASCADE与PROTECT
CASCADE:这是默认选项,表示级联删除,无需显式指定。 PROTECT:保护模式,删除时若存在关联记录,会抛出ProtectedError错误。 SET_NULL:置空模式,删除时外键字段设为空,前提是定义字段时允许blank=True和null=True。 SET_DEFAULT:置默认值,删除时外键字段设为默认值,因此定义外键时需指定默认值。 SET():自定义一个值,该值通常是对应的实体对象。
SET_NULL与SET_DEFAULT
3. SET()的使用
自定义SET()函数示例
def get_sentinel_user():
return get_user_model().objects.get_or_create(username='deleted')[0]
class MyModel(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.SET(get_sentinel_user),
)
ManyToManyField与through参数
4. ManyToMany参数(through, db_constraint)
ManyToMany through示例
class Book(models.Model):
name=models.CharField(max_length=20)
authors=models.ManyToMany('Author',through='Score')
class Author(models.Model):
name=models.CharField(max_length=20)
class Score(models.Model):
book=models.ForeignKey('Book')
author=models.ForeignKey('Author')
socre=models.IntegerField()
如果仅使用ManyToManyField,Django会自动创建第三张关联表,可通过book.authors字段进行增删查改(add、all、set、remove)。但此时无法为第三张表添加自定义字段。
如果不使用ManyToManyField,而是通过中间表(如Score)操作,虽然可以执行相关逻辑,但Book和Author表之间将失去直接联系,导致查询变得繁琐。
使用authors=models.ManyToManyField('Author', through='Score')后,既方便查询,又支持业务需求,可添加所需字段。
db_constraint与相关参数
5. db_constraint
设置db_constraint=False,可保留跨表查询的便利(如双下划线跨表查询),但不再对字段施加约束。许多公司采用此配置以避免报错,因为Field对象既负责约束,也建立表间关系。
limit_choices_to:限制关联字段的对象范围。
related_name:反向查询字段可自定义名称,无需使用表名小写形式。
db_table:指定第三张表的名称。
models.ForeignKey(AuthModel, null=True, blank=True, on_delete=models.SET_NULL, db_constraint=False)
总结与建议
5. 总结
若两个表存在关联,首先设置db_constraint=False以切断约束,但保留连表查询功能;其次设置null=True和blank=True,并确保on_delete=models.SET_NULL。这样删除主表数据时,不会影响其他关联表的数据完整性。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









