1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

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

This commit is contained in:
Jeremy Stretch
2020-09-15 13:36:36 -04:00
parent 08c492f1f4
commit 6694ec78bc

View File

@ -8,13 +8,13 @@ from django.core.exceptions import FieldError, MultipleObjectsReturned, ObjectDo
from django.db import transaction
from django.db.models import ManyToManyField, ProtectedError
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.permissions import BasePermission
from rest_framework.relations import PrimaryKeyRelatedField, RelatedField
from rest_framework.response import Response
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
@ -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
#
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.
"""
@ -408,6 +450,14 @@ class ModelViewSet(_ModelViewSet):
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):
"""
Wrap DRF's DefaultRouter to return an alphabetized list of endpoints.