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

Django REST framework中覆盖模型DELETE方法实现软删并保留外键数据

问题1:软删除方案在DRF中的可行性及实现方法

该方案完全可行,且是Django生态中非常成熟的实现方案,具体实现步骤如下:

步骤1:修改Product模型,新增软删除相关字段和自定义管理器

重写模型自带的delete方法,默认将删除操作改为标记删除状态,同时自定义查询管理器,正常查询时自动过滤已删除的商品,避免已停售商品出现在前台列表、下单等接口中。

from django.db import models
from django.utils import timezone

# 自定义软删除查询管理器
class SoftDeleteManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(is_deleted=False)

class Product(models.Model):
    # 原有字段保持不变
    name = models.CharField(max_length=100)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    # 新增软删除字段
    is_deleted = models.BooleanField(default=False, verbose_name="是否删除")
    deleted_at = models.DateTimeField(null=True, blank=True, verbose_name="删除时间")

    # 默认查询管理器自动过滤已删除商品
    objects = SoftDeleteManager()
    # 额外提供全量查询管理器,用于订单关联、审计等场景查询已删除商品
    all_objects = models.Manager()

    def delete(self, *args, **kwargs):
        # 默认执行软删除
        self.is_deleted = True
        self.deleted_at = timezone.now()
        self.save()
        # 可选:传参支持硬删除
        if kwargs.pop('hard_delete', False):
            return super().delete(*args, **kwargs)

步骤2:DRF视图层适配

如果使用ModelViewSet,不需要额外修改销毁逻辑,调用instance.delete()时会自动执行软删除逻辑,也可以显式重写destroy方法做自定义控制:

from rest_framework import viewsets, status
from rest_framework.response import Response
from .models import Product
from .serializers import ProductSerializer

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        instance.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

该方案不会触发原有外键的on_delete=SET_NULL规则,因为未真实删除Product表的记录,Order中关联的外键值完全保留,满足订单记录不丢失的需求。如果需要查询订单对应的商品信息,可通过Product.all_objects.get(id=order.product_id)获取包括已删除在内的全量商品数据。


问题2:其他实现需求的最佳实践

除软删除外,还有以下成熟方案可按需选择:

  • 商品快照冗余存储:这是电商订单场景的首选方案,直接在Order模型中冗余存储下单时点的商品核心信息,不受后续商品修改、删除的影响,完全符合审计日志的准确性要求。
    代码示例:
    class Order(models.Model):
        product = models.ForeignKey(Product, blank=True, null=True, on_delete=models.SET_NULL)
        # 冗余存储商品快照,可根据业务需求存JSON或者单独拆分为字段
        product_name = models.CharField(max_length=100, blank=True, verbose_name="下单时商品名称")
        product_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, verbose_name="下单时商品价格")
        product_snapshot = models.JSONField(default=dict, verbose_name="完整商品快照")
    
    下单时直接将当前Product的对应信息写入冗余字段即可,后续即使硬删除Product,订单的核心信息也完全保留。
  • 外键规则改为SET_DEFAULT:提前在Product表中创建一条固定的「已下架商品」默认记录,将Order外键的on_delete规则改为models.SET_DEFAULT,默认指向这条记录,删除商品时关联订单的外键会自动指向该默认记录,不会被置空。该方案适合不需要保留原商品具体信息的轻量化场景。
  • 归档下架商品:单独创建ArchivedProduct归档表,删除商品时将原商品数据迁移到归档表中,Order模型新增归档商品外键字段,删除时自动关联到归档记录,适合商品数据量极大、需要降低主表查询压力的场景。

内容的提问来源于stack exchange,提问作者R. Liu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 10:45:02