django数据模型中关于on_delete的使用

本文深入探讨了在数据库模型中对外键进行删除操作时的多种策略,包括级联删除、保护模式、置空模式、置默认值及自定义值等,并通过Python的Django框架示例代码展示了不同策略的应用场景。

一、外键的删除

关于on_delete的总结

1、常见的使用方式(设置为null)

class ApiList(models.Model):
	desc = models.CharField(max_length=255, verbose_name="接口描述")
	keyword = models.CharField(max_length=100, verbose_name="请求关键字")
	response = models.TextField(verbose_name="响应结果")
	api = models.ForeignKey(Api, blank=True, null=True, on_delete=models.SET_NULL, verbose_name="所属接口")
	status = models.IntegerField(default=1, verbose_name="状态")
	create_at = models.CharField(max_length=20, verbose_name="创建时间")
	update_at = models.CharField(max_length=20, verbose_name="更新时间")

2、关于别的属性的介绍

  • CASCADE:这就是默认的选项,级联删除,你无需显性指定它。
  • PROTECT: 保护模式,如果采用该选项,删除的时候,会抛出ProtectedError错误。
  • SET_NULL: 置空模式,删除的时候,外键字段被设置为空,前提就是blank=True, null=True,定义该字段的时候,允许为空。
  • SET_DEFAULT: 置默认值,删除的时候,外键字段设置为默认值,所以定义外键的时候注意加上一个默认值。
  • SET(): 自定义一个值,该值当然只能是对应的实体了

3、补充说明:关于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),
    )
<think>我们正在讨论Django模型中的on_delete参数,它用于定义当外键引用的对象被删除时,应该如何处理当前对象的外键字段。根据引用[1]、[3]和[5],on_delete是ForeignKey(一对多)和OneToOneField(一对一)的必需参数。它决定了当被引用的对象被删除时,引用它的对象的行为。常见的选项包括:-CASCADE:级联删除。当被引用的对象被删除时,引用它的对象也会被删除。-PROTECT:保护模式。如果还有对象引用它,则阻止删除被引用的对象。-SET_NULL:设置为空。需要设置字段允许为空(null=True)。当被引用的对象被删除时,将外键字段设置为NULL。-SET_DEFAULT:设置为默认值。需要设置字段的默认值(default=...)。当被引用的对象被删除时,将外键字段设置为默认值。- SET():可以指定一个函数或可调用对象,返回一个值用于设置外键字段。-DO_NOTHING:什么也不做。数据库层面可能会抛出完整性错误,除非手动处理。引用[1]中给出了SET()的示例:使用一个函数返回一个“已删除”用户,当用户被删除时,将外键设置为这个特定的用户。引用[5]展示了SET_NULL的用法:当作者被删除时,将书籍的作者字段设置为NULL。下面我们将详细说明每个选项的用途,并给出示例。</think>### Django 模型字段 `on_delete` 参数详解 `on_delete` 是 Django 模型中外键(`ForeignKey`)和一对一(`OneToOneField`)字段的**必需参数**,用于定义当被引用对象被删除时,当前对象的处理逻辑[^1][^3][^5]。 --- #### 核心作用与机制 | 特性 | 说明 | |------|------| | **关联关系维护** | 处理跨表数据一致性(如用户删除后其文章的处理) | | **数据库约束** | 实现数据库层面的级联操作或保护机制 | | **防止数据孤岛** | 避免存在无效外键指向已删除对象 | --- #### 常用选项及示例 ##### 1. `models.CASCADE`:级联删除 **行为**:删除被引用对象时,同时删除关联对象 ```python class Comment(models.Model): # 用户删除时,其所有评论自动删除 user = models.ForeignKey(User, on_delete=models.CASCADE) ``` ##### 2. `models.PROTECT`:防止删除 **行为**:阻止删除被引用的对象(存在关联对象时抛出`ProtectedError`) ```python class Profile(models.Model): # 阻止删除有档案的用户 user = models.OneToOneField(User, on_delete=models.PROTECT) ``` ##### 3. `models.SET_NULL`:设为空值 **行为**:外键字段设为 `NULL`(需设置 `null=True`) ```python class Book(models.Model): # 作者删除时,书籍作者字段设为 NULL author = models.ForeignKey(Author, null=True, on_delete=models.SET_NULL) ``` ##### 4. `models.SET_DEFAULT`:设为默认值 **行为**:外键字段设为默认值(需设置 `default=...`) ```python class Order(models.Model): # 客户删除时,订单归属默认客户 customer = models.ForeignKey(Customer, on_delete=models.SET_DEFAULT, default=1) ``` ##### 5. `models.SET()`:自定义处理逻辑 **行为**:通过函数动态指定新值[^1] ```python def get_deleted_user(): # 创建/获取"已删除"占位用户 return User.objects.get_or_create(username="deleted")[0] class Post(models.Model): # 用户删除时,帖子作者设为占位用户 author = models.ForeignKey(User, on_delete=models.SET(get_deleted_user)) ``` ##### 6. `models.DO_NOTHING`:不干预 **行为**:数据库不自动处理(需手动维护数据一致性) ```python class LogEntry(models.Model): # 需手动处理用户删除后的日志 user = models.ForeignKey(User, on_delete=models.DO_NOTHING) ``` --- #### 使用场景对比 | 选项 | 适用场景 | 数据库影响 | |------|----------|------------| | `CASCADE` | 强关联数据(如评论-文章) | 自动删除关联数据 | | `PROTECT` | 关键数据保护(如用户-账单) | 阻止删除操作 | | `SET_NULL` | 可选关联数据(如书籍-绝版作者) | 外键置空 | | `SET()` | 需保留历史记录(如订单-客户) | 自定义值替换 | --- #### 最佳实践 1. **必选参数**:所有 `ForeignKey` 和 `OneToOneField` 必须显式声明 `on_delete`[^3] 2. **与 `null` 配合**:使用 `SET_NULL` 时需设置 `null=True`[^5] 3. **性能考量**: - `CASCADE` 在关联数据量大时可能影响性能 - `SET()` 中的函数应避免复杂查询 4. **数据完整性**: ```python # 错误示例:缺少null=True将导致运行时错误 author = models.ForeignKey(Author, on_delete=models.SET_NULL) # ❌ 抛出异常 # 正确示例 author = models.ForeignKey(Author, null=True, on_delete=models.SET_NULL) # ✅ ``` --- #### 实际应用案例 **用户-博客系统模型** ```python from django.db import models from django.contrib.auth.models import User def get_archived_category(): return Category.objects.get_or_create(name="Archived")[0] class Category(models.Model): name = models.CharField(max_length=50) class Article(models.Model): # 分类删除时文章移至"Archived"类 category = models.ForeignKey(Category, on_delete=models.SET(get_archived_category)) # 用户删除时保留文章(作者置空) author = models.ForeignKey(User, null=True, on_delete=models.SET_NULL) # 标签删除时不影响文章 tags = models.ManyToManyField("Tag") # 多对多无需on_delete class Tag(models.Model): name = models.CharField(max_length=30) ``` > 合理使用 `on_delete` 能有效维护数据完整性,避免出现"悬空外键"[^2][^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值