From cc93e81f1245f40476a0eb9ed881880644fc5f82 Mon Sep 17 00:00:00 2001 From: rajanmandanka Date: Fri, 30 Jun 2017 12:21:26 +0530 Subject: [PATCH 1/5] Change GenericAPIView to GenericViewSet Change GenericAPIView to GenericViewSet --- rest_framework_bulk/generics.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) 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) From 9976ea164789399229e8b0110285ac8d6a1634ae Mon Sep 17 00:00:00 2001 From: rajanmandanka Date: Fri, 30 Jun 2017 12:28:59 +0530 Subject: [PATCH 2/5] Update README.rst --- README.rst | 77 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/README.rst b/README.rst index af70822..fcec85d 100644 --- a/README.rst +++ b/README.rst @@ -41,24 +41,56 @@ or from source code:: Example ------- -The bulk views (and mixins) are very similar to Django REST Framework's own -generic views (and mixins):: +The bulk views (and mixins) are very similar to Django REST Framework's own generic views (and mixins): - from rest_framework_bulk import ( - BulkListSerializer, - BulkSerializerMixin, - ListBulkCreateUpdateDestroyAPIView, - ) - class FooSerializer(BulkSerializerMixin, ModelSerializer): - class Meta(object): - model = FooModel - # only necessary in DRF3 - list_serializer_class = BulkListSerializer +Model.py +------ + +class FooModel(models.Model): + name = models.CharField(max_length=32) + +Serializer.py +------ + +from rest_framework_bulk.drf3.serializers import BulkSerializerMixin , BulkListSerializer +class FooSerializer(BulkSerializerMixin, serializers.ModelSerializer): + class Meta(object): + model = FooModel + list_serializer_class = BulkListSerializer + fields = '__all__' + +urls.py ( In-app url ) +------ + +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 + + +views.py +------ + +from rest_framework_bulk.generics import ListBulkCreateUpdateDestroyAPIView +from .models import FooModel +from .serializers import FooSerializer + +class FooViewSet(ListBulkCreateUpdateDestroyAPIView): + queryset = FooModel.objects.all() + serializer_class = FooSerializer + permission_classes = (UserPermission,) - class FooView(ListBulkCreateUpdateDestroyAPIView): - queryset = FooModel.objects.all() - serializer_class = FooSerializer The above will allow to create the following queries @@ -96,21 +128,6 @@ The above will allow to create the following queries # delete queryset (see notes) DELETE -Router ------- - -The bulk router can automatically map the bulk actions:: - - from rest_framework_bulk.routes import BulkRouter - - class UserViewSet(BulkModelViewSet): - model = User - - def allow_bulk_destroy(self, qs, filtered): - """Don't forget to fine-grain this method""" - - router = BulkRouter() - router.register(r'users', UserViewSet) DRF3 ---- From 3957f534738c23924929a6d48be868f7d6b1f02b Mon Sep 17 00:00:00 2001 From: rajanmandanka Date: Fri, 30 Jun 2017 12:56:52 +0530 Subject: [PATCH 3/5] Update README.rst --- README.rst | 151 ++++++++++++++++------------------------------------- 1 file changed, 44 insertions(+), 107 deletions(-) diff --git a/README.rst b/README.rst index fcec85d..0b36a17 100644 --- a/README.rst +++ b/README.rst @@ -41,56 +41,49 @@ or from source code:: Example ------- -The bulk views (and mixins) are very similar to Django REST Framework's own generic views (and mixins): +The bulk views (and mixins) are very similar to Django REST Framework's own +generic views (and mixins):: + + from rest_framework_bulk.drf3.serializers import ( + BulkListSerializer, + BulkSerializerMixin, + ) -Model.py ------- - -class FooModel(models.Model): - name = models.CharField(max_length=32) - -Serializer.py ------- - -from rest_framework_bulk.drf3.serializers import BulkSerializerMixin , BulkListSerializer -class FooSerializer(BulkSerializerMixin, serializers.ModelSerializer): - class Meta(object): - model = FooModel - list_serializer_class = BulkListSerializer - fields = '__all__' + from rest_framework_bulk.generics import ListBulkCreateUpdateDestroyAPIView + + # **serializer.py** -urls.py ( In-app url ) ------- - -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) + class FooSerializer(BulkSerializerMixin, ModelSerializer): + class Meta(object): + model = FooModel + # only necessary in DRF3 + fields = '__all__' + list_serializer_class = BulkListSerializer -urlpatterns = [] -urlpatterns += router.urls -urlpatterns += router2.urls + # **views.py** + class FooViewSet(ListBulkCreateUpdateDestroyAPIView): + queryset = FooModel.objects.all() + serializer_class = FooSerializer -views.py ------- -from rest_framework_bulk.generics import ListBulkCreateUpdateDestroyAPIView -from .models import FooModel -from .serializers import FooSerializer + # **urls.py** -class FooViewSet(ListBulkCreateUpdateDestroyAPIView): - queryset = FooModel.objects.all() - serializer_class = FooSerializer - permission_classes = (UserPermission,) + 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 @@ -128,74 +121,18 @@ The above will allow to create the following queries # delete queryset (see notes) DELETE +Router +------ -DRF3 ----- +The bulk router can automatically map the bulk actions:: -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: + from rest_framework_bulk.routes import BulkRouter -* 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 UserViewSet(BulkModelViewSet): + model = User - 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. + """Don't forget to fine-grain this method""" + + router = BulkRouter() + router.register(r'users', UserViewSet) From 0dd210602ac87a4ef0236e5fd55a901b2a0126b6 Mon Sep 17 00:00:00 2001 From: rajanmandanka Date: Fri, 30 Jun 2017 13:00:11 +0530 Subject: [PATCH 4/5] Update README.rst --- README.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 0b36a17..5d34c34 100644 --- a/README.rst +++ b/README.rst @@ -52,7 +52,8 @@ generic views (and mixins):: from rest_framework_bulk.generics import ListBulkCreateUpdateDestroyAPIView - # **serializer.py** + serializer.py + ------------- class FooSerializer(BulkSerializerMixin, ModelSerializer): class Meta(object): @@ -61,14 +62,16 @@ generic views (and mixins):: fields = '__all__' list_serializer_class = BulkListSerializer - # **views.py** + views.py + -------- class FooViewSet(ListBulkCreateUpdateDestroyAPIView): queryset = FooModel.objects.all() serializer_class = FooSerializer - # **urls.py** + urls.py + ------- from rest_framework import routers from .views import UserViewSet , FooViewSet From f6b96e0e3cc2e7bcf84eb9336cdf4213c6d931e5 Mon Sep 17 00:00:00 2001 From: rajanmandanka Date: Fri, 30 Jun 2017 13:05:11 +0530 Subject: [PATCH 5/5] Update README.rst --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5d34c34..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 -------