1

I have a custom pagination class in a separate file and until now I have been importing it in a ListAPIView, but this time I tried with APIView, but it didn't work.

My pagination class:

class CustomPagination(PageNumberPagination):
    def get_paginated_response(self, data):
        return Response({
            'links': {
                'next': self.get_next_link(),
                'previous': self.get_previous_link()
            },
            'count': self.page.paginator.count,
            'page_size' : 15,
            'results': data
        })

I am trying to use custom pagination because I can have the count of the objects as well.

My view where I try to implement the pagination:

from apps.products.api.pagination import CustomPagination

class CouponView(APIView):
    permission_classes = [AllowAny]
    #pagination_class = CustomPagination


    def get(self,request,pk = None,*args,**kwargs):

        id = pk
        if id is not None:
            abc = Coupons.objects.get(id=id)
            serializer = CouponSerializer(abc)
            return serializer.data
        else:
            abc = Coupons.objects.all()
            paginator = CustomPagination()
            result_page = paginator.paginate_queryset(abc, request)
            serializer = CouponSerializer(result_page,many=True)
            return Response (serializer.data,status=status.HTTP_200_OK)
Reactoo
  • 916
  • 2
  • 12
  • 40

3 Answers3

1

APIView doesn't support this feature. You'll either need to leverage ListApiView or similar generics (such as RetrieveApiView), or use the ReadOnlyModelViewSet. These both support pagination, and give you get_object.

Your code seems to be implementing the basic ViewSet features (list + retrieve). The issue with the API views is that these two both use get, so they can't be combined into one view. Using a viewset will solve that.

class CouponReadOnly(ReadOnlyModelViewSet):
    pagination_class = SomeClass
    serializer_class = CouponSerializer
    queryset = Coupon.objects.all()

And then use a Router in your urls.py to link it up, and let the router generate the routes.

# in your urls.py --------------
router = SimpleRouter()
router.register("coupons", CouponReadOnly, "coupon")

urlpatterns = [...] # existing routes
urlpatterns += router.urls

If you want to do this manually with 2 views, then you can use the generics and manually create the paths, like you already are:

class CouponListView(ListAPIView):
    # you said this one already works

class CouponGetView(RetrieveAPIView):
    queryset = Coupon.objects.all()
    serializer_class = CouponSerializer


urlpatterns = [
    path("coupons/", CouponListView.as_view(), name="coupon-list"),
    path("coupons/<int:pk>", CouponGetView.as_view(), name="coupon-get"),
]
    
Andrew
  • 8,322
  • 2
  • 47
  • 70
  • hello @Andrew. I have solved it thanks. But I think we can use list and retrieve in a single api in APIView using logic of if id is not None just like above and it works fine. Being a senior engineer, one should be able to put all logics in a single api rather than creating multiple apis, in my view. – Reactoo Aug 13 '21 at 05:07
  • Thats hilarious. You do you, good luck with that! – Andrew Aug 13 '21 at 12:12
  • what is so funny? can you please explain? I am new to Django rest – Reactoo Aug 15 '21 at 05:17
1

You should use get_paginated_response in GenericAPIView for custom pagination.

from apps.products.api.pagination import CustomPagination
from rest_framework.generics import GenericAPIView


class CouponView(GenericAPIView):
    permission_classes = [AllowAny]    

    def get(self,request,pk = None,*args,**kwargs):

        id = pk
        if id is not None:
            abc = Coupons.objects.get(id=id)
            serializer = CouponSerializer(abc)
            return serializer.data
        else:
            abc = Coupons.objects.all()
            self.pagination_class = CustomPagination
            page = self.paginate_queryset(abc)
            serializer = serializer(page, many=True, context={'request': request})
            return self.get_paginated_response(serializer.data)

However, let apply the correct RESTFul API to get list and detail, so you will not custom more.

  • List coupons: GET /api/coupons/
  • Get coupon detail: GET /api/coupons/<coupon_id/
class CouponView(ListAPIView, RetrieveAPIView):
    permission_classes = [AllowAny]   
    pagination_class = CustomPagination
    queryset = Coupons.objects.all()
    serializer_class = CouponSerializer 
Huy Chau
  • 2,178
  • 19
  • 26
0

I did the following and it worked:

def get(self,request,pk = None,*args,**kwargs):

        id = pk
        if id is not None:
            abc = Coupons.objects.get(id=id)
            serializer = CouponSerializer(abc)
            return serializer.data
        else:
            abc = Coupons.objects.all()
            paginator = CustomPagination()
            result_page = paginator.paginate_queryset(abc,request)
            serializer = CouponSerializer(result_page,many=True)
            # return Response (serializer.data,status=status.HTTP_200_OK)
            return paginator.get_paginated_response(serializer.data)
Reactoo
  • 916
  • 2
  • 12
  • 40