Pagination in Django-Rest-Framework using API-View

后端 未结 4 785
刺人心
刺人心 2020-12-08 08:34

I currently have an API view setup as follows:

class CartView(APIView):
    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permiss         


        
相关标签:
4条回答
  • 2020-12-08 08:51

    When using regular APIView, you need to use Django's own Paginator class.

    Django Pagination in Views

    In your case you can paginate queryset before sending it to serializer.

    Something like this:

    def get(self, request, format=None):
        try:
            cart = request.user.cart
        except Cart.DoesNotExist:
            cart = Cart.objects.create(user=request.user)
        cart_details = cart.cart_details.all()
    
        paginator = Paginator(cart_details, 10)
        page = request.GET.get('page')
    
        try:
            cart_details = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            cart_details = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            cart_details = paginator.page(paginator.num_pages)
        serializer = CartDetailSerializer(cart_details, many=True, fields=['id', 'item', 'quantity', 'product_type'])
        return Response(serializer.data)
    

    Hope this helps.

    0 讨论(0)
  • 2020-12-08 09:07

    While the way rayy mentions is a possibility, django-rest-framework can handle this internally with some additional features that make working with your API much easier. (*note django-rest-framework's pagination is built from the Django paginator from django.core.paginator)

    Right after what you quoted is the key information to solving this problem:

    Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular APIView, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the mixins.ListMixin and generics.GenericAPIView classes for an example.

    Slight correction to what is stated there: look at the ListModelMixin.

    If you go to these two links you can see the source code for the above files: generics.py mixins.py

    What you need to do is include something like the following to get pagination to work in the APIView (**note: this code is untested but the idea is correct. There is also a better way of writing this rather than having to include the code in every view but I will leave that up to you to keep my answer short and understandable):

    from __future__ import absolute_import
    # if this is where you store your django-rest-framework settings
    from django.conf import settings
    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    from .models import Cart 
    
    class CartView(APIView):
        pagination_class = settings.DEFAULT_PAGINATION_CLASS
    
        def get(self, request, format=None):
            #assuming every other field in the model has a default value    
            cart = Cart.objects.get_or_create(user=request.user)
    
            #for a clear example
            cart_details = Cart.objects.all()
    
            page = self.paginate_queryset(cart_details)
            if page is not None:
                serializer = CartDetailSerializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = CartDetailSerializer(cart_details, many=True)
            return Response(serializer.data)
    
        @property
        def paginator(self):
            """
            The paginator instance associated with the view, or `None`.
            """
            if not hasattr(self, '_paginator'):
                if self.pagination_class is None:
                    self._paginator = None
                else:
                    self._paginator = self.pagination_class()
            return self._paginator
    
        def paginate_queryset(self, queryset):
            """
            Return a single page of results, or `None` if pagination is disabled.
            """
            if self.paginator is None:
                return None
            return self.paginator.paginate_queryset(queryset, self.request, view=self)
    
        def get_paginated_response(self, data):
            """
            Return a paginated style `Response` object for the given output data.
            """
            assert self.paginator is not None
            return self.paginator.get_paginated_response(data)
    

    I hope this was of more help to you and others who come across this post.

    0 讨论(0)
  • 2020-12-08 09:08

    I am using DRF version 3.6.2. You don't need to code so much. Just use this simple steps.

     class ProductPagination(PageNumberPagination):
            page_size = 5
    
        class product_api(generics.ListCreateAPIView):    
                queryset = Products.objects.all()
                serializer_class = product_serilizer
                pagination_class = ProductPagination
    

    if you want search functionality by getting method, you can write below code

    class ProductPagination(PageNumberPagination):
            page_size = 5
    
    class product_api(generics.ListCreateAPIView):
        queryset = Products.objects.all()
        serializer_class = product_serilizer
        pagination_class = SearchProductPagination    
    
        def get_queryset(self):
            qs = super(product_search_api,self).get_queryset()
            searched_product = self.request.query_params.get('searched_product',None)
            if search:
                qs = Products.objects.filter(Q(product_name__icontains= searched_product))
            return qs
    
    0 讨论(0)
  • 2020-12-08 09:18

    I prefer extending the Paginator class, here is how it would look:

    from rest_framework import status
    from rest_framework.exceptions import NotFound as NotFoundError
    from rest_framework.pagination import PageNumberPagination # Any other type works as well
    from rest_framework.response import Response
    from rest_framework.views import APIView
    
    class CustomPaginator(PageNumberPagination):
        page_size = 10 # Number of objects to return in one page
    
        def generate_response(self, query_set, serializer_obj, request):
            try:
                page_data = self.paginate_queryset(query_set, request)
            except NotFoundError:
                return Response({"error": "No results found for the requested page"}, status=status.HTTP_400_BAD_REQUEST)
    
            serialized_page = serializer_obj(page_data, many=True)
            return self.get_paginated_response(serialized_page.data)
    
    class CartView(APIView):
    
        def get(self, request, format=None):
            cart_details = Cart.objects.filter(user=request.user) # or any other query
            paginator = CustomPaginator()
            response = paginator.generate_response(cart_details, CartDetailSerializer, request)
            return response
    
    0 讨论(0)
提交回复
热议问题