You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置DestroyAPIView实现BModel软删除而非真实删除?

实现Django-Rest-Framework中BModel的软删除需求

先直接回答你的两个疑问:

  1. 是的,def delete(self, using=None, keep_parents=False):确实是BModel的实例方法——它继承自Django的models.Model基类,每个模型实例都自带这个方法,作用是删除当前实例。
  2. 重写这个实例方法是实现软删除的可行方案,但还要配合调整查询逻辑,避免已标记为删除的实例出现在列表接口中,同时还要注意DRF视图的调用逻辑。

接下来给你一步步的实现方案:

1. 修正模型的delete方法,实现软删除逻辑

你之前的delete方法里只写了pass,现在要改成将status设为deleted并保存实例,不要调用父类的delete方法,否则会执行真实删除:

class BModel(models.Model):
    # 建议给status字段加上choices,让取值更规范
    STATUS_CHOICES = (
        ("is_active", "Active"),
        ("deleted", "Deleted"),
    )
    name = models.CharField(max_length=11)
    status = models.CharField(max_length=20, default="is_active", choices=STATUS_CHOICES)
    a = models.ForeignKey(AModel, on_delete=models.CASCADE)  # Django3.2+需指定on_delete参数

    def delete(self, using=None, keep_parents=False):
        # 标记为删除状态
        self.status = "deleted"
        self.save(using=using)
        # 不要调用super().delete(),否则会真实删除实例

2. 调整列表视图,过滤已软删除的实例

你的BModelListAPIView现在返回所有实例,包括已标记为deleted的,所以要修改queryset只返回活跃状态的实例:

class BModelListAPIView(ListAPIView):
    serializer_class = BModelSerializer
    permission_classes = []
    # 只返回status为is_active的实例
    queryset = BModel.objects.filter(status="is_active")

更优雅的方式:自定义模型管理器

如果希望所有默认的查询都自动过滤已删除实例(除了特殊场景),可以自定义模型管理器:

class BModelManager(models.Manager):
    def get_queryset(self):
        # 默认只返回活跃状态的实例
        return super().get_queryset().filter(status="is_active")

class BModel(models.Model):
    # ... 字段定义
    # 替换默认的objects管理器
    objects = BModelManager()
    # 保留一个能获取所有实例(包括已删除)的管理器,方便特殊场景使用
    all_objects = models.Manager()

这样BModel.objects.all()就会自动过滤掉deleted的实例,你的列表视图可以直接用queryset = BModel.objects.all(),不需要额外加过滤条件。

3. 验证DRF的删除视图行为

你的BModelDestroyAPIView继承自DestroyAPIView,它的逻辑是:

  • 通过get_object()获取要删除的实例
  • 调用实例的delete()方法
  • 返回204状态码

所以当你重写了实例的delete方法后,调用这个接口就会自动触发软删除,而不是真实删除,完全符合你的需求。

额外注意:批量删除的场景

如果后续需要批量删除(比如用BModel.objects.filter(...).delete()),这时候调用的是QuerySet的delete方法,不会触发每个实例的delete方法。如果要处理这种场景,需要重写QuerySet的delete方法:

class BModelQuerySet(models.QuerySet):
    def delete(self):
        # 批量更新status为deleted,而不是真实删除
        return self.update(status="deleted")

# 在模型管理器中使用这个自定义QuerySet
class BModelManager(models.Manager):
    def get_queryset(self):
        return BModelQuerySet(self.model, using=self._db).filter(status="is_active")

这样不管是单个实例删除还是批量删除,都会执行软删除逻辑。

内容的提问来源于stack exchange,提问作者1243916142

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:43:37