123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- from __future__ import unicode_literals, print_function
- from django.core.exceptions import ValidationError
- from rest_framework import status
- from rest_framework.mixins import CreateModelMixin
- from rest_framework.response import Response
- __all__ = [
- 'BulkCreateModelMixin',
- 'BulkDestroyModelMixin',
- 'BulkUpdateModelMixin',
- ]
- class BulkCreateModelMixin(CreateModelMixin):
- """
- Either create a single or many model instances in bulk by using the
- Serializers ``many=True`` ability from Django REST >= 2.2.5.
- .. note::
- This mixin uses the same method to create model instances
- as ``CreateModelMixin`` because both non-bulk and bulk
- requests will use ``POST`` request method.
- """
- def create(self, request, *args, **kwargs):
- bulk = isinstance(request.DATA, list)
- if not bulk:
- return super(BulkCreateModelMixin, self).create(request, *args, **kwargs)
- else:
- serializer = self.get_serializer(data=request.DATA, many=True)
- if serializer.is_valid():
- for obj in serializer.object:
- self.pre_save(obj)
- self.object = serializer.save(force_insert=True)
- for obj in self.object:
- self.post_save(obj, created=True)
- return Response(serializer.data, status=status.HTTP_201_CREATED)
- return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- class BulkUpdateModelMixin(object):
- """
- Update model instances in bulk by using the Serializers
- ``many=True`` ability from Django REST >= 2.2.5.
- """
- def get_object(self, queryset=None):
- lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
- if any((lookup_url_kwarg in self.kwargs,
- self.pk_url_kwarg in self.kwargs,
- self.slug_url_kwarg in self.kwargs)):
- return super(BulkUpdateModelMixin, self).get_object(queryset)
- # If the lookup_url_kwarg (or other deprecated variations)
- # are not present, get_object() is most likely called
- # as part of metadata() which by default simply checks
- # for object permissions and raises permission denied if necessary.
- # Here we don't need to check for general permissions
- # and can simply return None since general permissions
- # are checked in initial() which always gets executed
- # before any of the API actions (e.g. create, update, etc)
- return
- def bulk_update(self, request, *args, **kwargs):
- partial = kwargs.pop('partial', False)
- # restrict the update to the filtered queryset
- serializer = self.get_serializer(self.filter_queryset(self.get_queryset()),
- data=request.DATA,
- many=True,
- partial=partial)
- if serializer.is_valid():
- try:
- for obj in serializer.object:
- self.pre_save(obj)
- except ValidationError as err:
- # full_clean on model instances may be called in pre_save
- # so we have to handle eventual errors.
- return Response(err.message_dict, status=status.HTTP_400_BAD_REQUEST)
- self.object = serializer.save(force_update=True)
- for obj in self.object:
- self.post_save(obj, created=False)
- return Response(serializer.data, status=status.HTTP_200_OK)
- return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- def partial_bulk_update(self, request, *args, **kwargs):
- kwargs['partial'] = True
- return self.bulk_update(request, *args, **kwargs)
- class BulkDestroyModelMixin(object):
- """
- Destroy model instances.
- """
- def allow_bulk_destroy(self, qs, filtered):
- """
- Hook to ensure that the bulk destroy should be allowed.
- By default this checks that the destroy is only applied to
- filtered querysets.
- """
- return qs is not filtered
- def bulk_destroy(self, request, *args, **kwargs):
- qs = self.get_queryset()
- filtered = self.filter_queryset(qs)
- if not self.allow_bulk_destroy(qs, filtered):
- return Response(status=status.HTTP_400_BAD_REQUEST)
- for obj in filtered:
- self.pre_delete(obj)
- obj.delete()
- self.post_delete(obj)
- return Response(status=status.HTTP_204_NO_CONTENT)
|