如何在DRF中发送DELETE请求体并实现带过滤的批量删除
解决DRF中批量删除仅允许过滤后查询集的问题
嘿,我来帮你搞定这个批量删除的需求!既然你已经在用django-rest-framework-bulk的BulkModelViewSet,那咱们只需要在视图里加一层校验逻辑,确保只有过滤后的数据集才能被批量删除,不能直接删全表。
第一步:确保依赖正确安装配置
首先确认你已经装了库,并且加到了项目配置里:
pip install django-rest-framework-bulk
然后在settings.py的INSTALLED_APPS中添加:
INSTALLED_APPS = [ # ... 其他应用 'rest_framework_bulk', ]
第二步:自定义BulkModelViewSet,添加校验逻辑
核心思路是重写bulk_destroy方法,先拿到过滤后的查询集,再判断是否是全量数据,拒绝无过滤的批量删除。这里分两种常见场景处理:
场景1:通过URL参数过滤后删除(比如按team过滤)
这种情况下,前端不需要传请求体,只需要通过URL参数过滤,然后发送DELETE请求:
from rest_framework_bulk import BulkModelViewSet from rest_framework.response import Response from rest_framework import status from rest_framework.filters import DjangoFilterBackend, SearchFilter from .models import Hero # 换成你的模型 from .serializers import HeroSerializer # 换成你的序列化器 class HeroBulkViewSet(BulkModelViewSet): queryset = Hero.objects.all() serializer_class = HeroSerializer # 配置过滤后端,允许按字段过滤或搜索 filter_backends = [DjangoFilterBackend, SearchFilter] filterset_fields = ['team'] # 允许按team过滤 search_fields = ['first_name', 'second_name'] # 支持模糊搜索 def bulk_destroy(self, request, *args, **kwargs): # 获取经过URL参数过滤后的查询集 filtered_queryset = self.filter_queryset(self.get_queryset()) # 校验:如果过滤后的查询集等于全量数据,说明没有加过滤条件,拒绝删除 if filtered_queryset.count() == Hero.objects.count(): return Response( {"detail": "批量删除仅支持过滤后的数据集,禁止删除全部数据!"}, status=status.HTTP_403_FORBIDDEN ) # 执行批量删除 self.perform_bulk_destroy(filtered_queryset) return Response(status=status.HTTP_204_NO_CONTENT)
场景2:通过DELETE请求体传ID列表删除(同时支持URL过滤)
如果你的需求是前端通过请求体传要删除的ID数组(比如你提供的JSON格式),那可以调整逻辑,同时校验请求体的ID和URL过滤条件:
def bulk_destroy(self, request, *args, **kwargs): # 从请求体中提取要删除的ID列表 delete_ids = [item.get('id') for item in request.data] if not delete_ids: return Response( {"detail": "请提供要删除的记录ID列表!"}, status=status.HTTP_400_BAD_REQUEST ) # 先应用URL过滤条件,再筛选出请求体中的ID filtered_queryset = self.filter_queryset(self.get_queryset()).filter(id__in=delete_ids) # 校验:如果要删除的是全量数据,拒绝操作 if filtered_queryset.count() == Hero.objects.count(): return Response( {"detail": "批量删除仅支持过滤后的数据集,禁止删除全部数据!"}, status=status.HTTP_403_FORBIDDEN ) self.perform_bulk_destroy(filtered_queryset) return Response(status=status.HTTP_204_NO_CONTENT)
第三步:序列化器配置
确保你的序列化器包含id字段,这样前端能正确传参:
from rest_framework import serializers from .models import Hero class HeroSerializer(serializers.ModelSerializer): class Meta: model = Hero fields = ['id', 'first_name', 'second_name', 'team']
测试示例
比如前端可以这样请求:
- 按team过滤后删除:发送
DELETE /heroes/?team=avengers - 传ID列表删除:发送
DELETE /heroes/,请求体为[{"id": "1"}, {"id": "2"}]
如果用户尝试直接删除全量数据(比如不带任何过滤参数,或者请求体包含所有ID),会返回403禁止访问。
内容的提问来源于stack exchange,提问作者Vasu Gaur
相关产品推荐
相关产品推荐

