فهرست منبع

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.