如何配置DestroyAPIView实现BModel软删除而非真实删除?
实现Django-Rest-Framework中BModel的软删除需求
先直接回答你的两个疑问:
- 是的,
def delete(self, using=None, keep_parents=False):确实是BModel的实例方法——它继承自Django的models.Model基类,每个模型实例都自带这个方法,作用是删除当前实例。 - 重写这个实例方法是实现软删除的可行方案,但还要配合调整查询逻辑,避免已标记为删除的实例出现在列表接口中,同时还要注意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
相关产品推荐
相关产品推荐

