瀏覽代碼

Implement support for bulk deletion of objects via a single REST API request

Jeremy Stretch 5 年之前
父節點
當前提交
6694ec78bc
共有 1 個文件被更改,包括 53 次插入3 次删除
  1. 53 3
      netbox/utilities/api.py

+ 53 - 3
netbox/utilities/api.py

@@ -8,13 +8,13 @@ from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDo
 from django.db import transaction
 from django.db import transaction
 from django.db.models import ManyToManyField, ProtectedError
 from django.db.models import ManyToManyField, ProtectedError
 from django.urls import reverse
 from django.urls import reverse
-from rest_framework import serializers
+from rest_framework import mixins, serializers, status
 from rest_framework.exceptions import APIException, ValidationError
 from rest_framework.exceptions import APIException, ValidationError
 from rest_framework.permissions import BasePermission
 from rest_framework.permissions import BasePermission
 from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
 from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
 from rest_framework.response import Response
 from rest_framework.response import Response
 from rest_framework.routers import DefaultRouter
 from rest_framework.routers import DefaultRouter
-from rest_framework.viewsets import ModelViewSet as _ModelViewSet
+from rest_framework.viewsets import GenericViewSet
 
 
 from .utils import dict_to_filter_params, dynamic_import
 from .utils import dict_to_filter_params, dynamic_import
 
 
@@ -291,11 +291,53 @@ class WritableNestedSerializer(serializers.ModelSerializer):
             )
             )
 
 
 
 
+class BulkDeleteSerializer(serializers.Serializer):
+    id = serializers.IntegerField()
+
+
+#
+# Mixins
+#
+
+class BulkDestroyModelMixin:
+    """
+    Support bulk deletion of objects using the list endpoint for a model. Accepts a DELETE action with a list of one
+    or more JSON objects, each specifying the numeric ID of an object to be deleted. For example:
+
+    DELETE /api/dcim/sites/
+    [
+        {"id": 123},
+        {"id": 456}
+    ]
+    """
+    def bulk_destroy(self, request):
+        serializer = BulkDeleteSerializer(data=request.data, many=True)
+        serializer.is_valid(raise_exception=True)
+
+        pk_list = [o['id'] for o in serializer.data]
+        qs = self.get_queryset().filter(pk__in=pk_list)
+
+        self.perform_bulk_destroy(qs)
+
+        return Response(status=status.HTTP_204_NO_CONTENT)
+
+    def perform_bulk_destroy(self, objects):
+        with transaction.atomic():
+            for obj in objects:
+                self.perform_destroy(obj)
+
+
 #
 #
 # Viewsets
 # Viewsets
 #
 #
 
 
-class ModelViewSet(_ModelViewSet):
+class ModelViewSet(mixins.CreateModelMixin,
+                   mixins.RetrieveModelMixin,
+                   mixins.UpdateModelMixin,
+                   mixins.DestroyModelMixin,
+                   mixins.ListModelMixin,
+                   BulkDestroyModelMixin,
+                   GenericViewSet):
     """
     """
     Accept either a single object or a list of objects to create.
     Accept either a single object or a list of objects to create.
     """
     """
@@ -408,6 +450,14 @@ class ModelViewSet(_ModelViewSet):
 
 
 class OrderedDefaultRouter(DefaultRouter):
 class OrderedDefaultRouter(DefaultRouter):
 
 
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+
+        # Extend the list view mappings to support the DELETE operation
+        self.routes[0].mapping.update({
+            'delete': 'bulk_destroy',
+        })
+
     def get_api_root_view(self, api_urls=None):
     def get_api_root_view(self, api_urls=None):
         """
         """
         Wrap DRF's DefaultRouter to return an alphabetized list of endpoints.
         Wrap DRF's DefaultRouter to return an alphabetized list of endpoints.