diff --git a/README.rst b/README.rst index af70822..6807c45 100644 --- a/README.rst +++ b/README.rst @@ -36,7 +36,7 @@ Using pip:: or from source code:: - $ pip install -e git+http://github.com/miki725/django-rest-framework-bulk#egg=djangorestframework-bulk + $ pip install -e git+http://github.com/rajanmandanka/django-rest-framework-bulk#egg=djangorestframework-bulk Example ------- @@ -44,22 +44,50 @@ Example The bulk views (and mixins) are very similar to Django REST Framework's own generic views (and mixins):: - from rest_framework_bulk import ( + + from rest_framework_bulk.drf3.serializers import ( BulkListSerializer, BulkSerializerMixin, - ListBulkCreateUpdateDestroyAPIView, ) + from rest_framework_bulk.generics import ListBulkCreateUpdateDestroyAPIView + + serializer.py + ------------- + class FooSerializer(BulkSerializerMixin, ModelSerializer): class Meta(object): model = FooModel # only necessary in DRF3 + fields = '__all__' list_serializer_class = BulkListSerializer - class FooView(ListBulkCreateUpdateDestroyAPIView): + views.py + -------- + + class FooViewSet(ListBulkCreateUpdateDestroyAPIView): queryset = FooModel.objects.all() serializer_class = FooSerializer + + urls.py + ------- + + from rest_framework import routers + from .views import UserViewSet , FooViewSet + from rest_framework_bulk.routes import BulkRouter + + + router = routers.DefaultRouter() + router.register(r'users', UserViewSet) + + router2 = BulkRouter() + router2.register(r'foo', FooViewSet) + + urlpatterns = [] + urlpatterns += router.urls + urlpatterns += router2.urls + The above will allow to create the following queries :: @@ -111,74 +139,3 @@ The bulk router can automatically map the bulk actions:: router = BulkRouter() router.register(r'users', UserViewSet) - -DRF3 ----- - -Django REST Framework made many API changes which included major changes -in serializers. As a result, please note the following in order to use -DRF-bulk with DRF3: - -* You must specify custom ``list_serializer_class`` if your view(set) - will require update functionality (when using ``BulkUpdateModelMixin``) -* DRF3 removes read-only fields from ``serializer.validated_data``. - As a result, it is impossible to correlate each ``validated_data`` - in ``ListSerializer`` with a model instance to update since ``validated_data`` - will be missing the model primary key since that is a read-only field. - To deal with that, you must use ``BulkSerializerMixin`` mixin in your serializer - class which will add the model primary key field back to the ``validated_data``. - By default ``id`` field is used however you can customize that field - by using ``update_lookup_field`` in the serializers ``Meta``:: - - class FooSerializer(BulkSerializerMixin, ModelSerializer): - class Meta(object): - model = FooModel - list_serializer_class = BulkListSerializer - update_lookup_field = 'slug' - -Notes ------ - -Most API urls have two URL levels for each resource: - -1. ``url(r'foo/', ...)`` -2. ``url(r'foo/(?P\d+)/', ...)`` - -The second url however is not applicable for bulk operations because -the url directly maps to a single resource. Therefore all bulk -generic views only apply to the first url. - -There are multiple generic view classes in case only a certail -bulk functionality is required. For example ``ListBulkCreateAPIView`` -will only do bulk operations for creating resources. -For a complete list of available generic view classes, please -take a look at the source code at ``generics.py`` as it is mostly -self-explanatory. - -Most bulk operations are pretty safe in terms of how they operate, -that is you explicitly describe all requests. For example, if you -need to update 3 specific resources, you have to explicitly identify -those resources in the request's ``PUT`` or ``PATCH`` data. -The only exception to this is bulk delete. Consider a ``DELETE`` -request to the first url. That can potentially delete all resources -without any special confirmation. To try to account for this, bulk delete -mixin allows to implement a hook to determine if the bulk delete -request should be allowed:: - - class FooView(BulkDestroyAPIView): - def allow_bulk_destroy(self, qs, filtered): - # custom logic here - - # default checks if the qs was filtered - # qs comes from self.get_queryset() - # filtered comes from self.filter_queryset(qs) - return qs is not filtered - -By default it checks if the queryset was filtered and if not will not -allow the bulk delete to complete. The logic here is that if the request -is filtered to only get certain resources, more attention was payed hence -the action is less likely to be accidental. On how to filter requests, -please refer to Django REST -`docs `_. -Either way, please use bulk deletes with extreme caution since they -can be dangerous. diff --git a/rest_framework_bulk/generics.py b/rest_framework_bulk/generics.py index 1f0711c..5fa164f 100644 --- a/rest_framework_bulk/generics.py +++ b/rest_framework_bulk/generics.py @@ -1,7 +1,7 @@ from __future__ import unicode_literals, print_function from rest_framework import mixins from rest_framework.generics import GenericAPIView -from rest_framework.viewsets import ModelViewSet +from rest_framework.viewsets import ModelViewSet , GenericViewSet from . import mixins as bulk_mixins @@ -26,13 +26,13 @@ # ################################################## # class BulkCreateAPIView(bulk_mixins.BulkCreateModelMixin, - GenericAPIView): + GenericViewSet): def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs) class BulkUpdateAPIView(bulk_mixins.BulkUpdateModelMixin, - GenericAPIView): + GenericViewSet): def put(self, request, *args, **kwargs): return self.bulk_update(request, *args, **kwargs) @@ -41,14 +41,14 @@ def patch(self, request, *args, **kwargs): class BulkDestroyAPIView(bulk_mixins.BulkDestroyModelMixin, - GenericAPIView): + GenericViewSet): def delete(self, request, *args, **kwargs): return self.bulk_destroy(request, *args, **kwargs) class ListBulkCreateAPIView(mixins.ListModelMixin, bulk_mixins.BulkCreateModelMixin, - GenericAPIView): + GenericViewSet): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -59,7 +59,7 @@ def post(self, request, *args, **kwargs): class ListCreateBulkUpdateAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, bulk_mixins.BulkUpdateModelMixin, - GenericAPIView): + GenericViewSet): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -77,7 +77,7 @@ class ListCreateBulkUpdateDestroyAPIView(mixins.ListModelMixin, mixins.CreateModelMixin, bulk_mixins.BulkUpdateModelMixin, bulk_mixins.BulkDestroyModelMixin, - GenericAPIView): + GenericViewSet): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -97,7 +97,7 @@ def delete(self, request, *args, **kwargs): class ListBulkCreateUpdateAPIView(mixins.ListModelMixin, bulk_mixins.BulkCreateModelMixin, bulk_mixins.BulkUpdateModelMixin, - GenericAPIView): + GenericViewSet): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -114,7 +114,7 @@ def patch(self, request, *args, **kwargs): class ListBulkCreateDestroyAPIView(mixins.ListModelMixin, bulk_mixins.BulkCreateModelMixin, bulk_mixins.BulkDestroyModelMixin, - GenericAPIView): + GenericViewSet): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) @@ -129,7 +129,7 @@ class ListBulkCreateUpdateDestroyAPIView(mixins.ListModelMixin, bulk_mixins.BulkCreateModelMixin, bulk_mixins.BulkUpdateModelMixin, bulk_mixins.BulkDestroyModelMixin, - GenericAPIView): + GenericViewSet): def get(self, request, *args, **kwargs): return self.list(request, *args, **kwargs)