Django外键on_delete与db_constraint详解:避免级联删除陷阱

一颗松果
一颗松果
发布时间:2026-10-13 | 4人浏览过
原创

本文详解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。这样删除主表数据时,不会影响其他关联表的数据完整性。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表