wake-up-neo.com

Paginierung im Django-Rest-Framework mit API-View

Ich habe derzeit eine API-Ansichtseinstellung wie folgt:

class CartView(APIView):
    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [IsAuthenticated, ]
    api_view = ['GET', 'POST']

    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()
        serializer = CartDetailSerializer(cart_details, many=True, fields=['id', 'item', 'quantity', 'product_type'])
        return Response(serializer.data)

Hier ist CartDetailSerializer ein normaler ModelSerializer.

Ich möchte diese API paginieren. In den Dokumenten von DRF fand ich jedoch Folgendes: 

Wenn Sie einen regulären APIView verwenden, müssen Sie die Paginierungs-API selbst aufrufen, um sicherzustellen, dass Sie eine paginierte Antwort zurückgeben. 

Es gibt kein Beispiel zum Paginieren einer regulären APIView-API.

Kann jemand ein Beispiel posten, das ich im obigen Szenario verwenden kann.

Vielen Dank.

12
apatel

Wenn Sie den regulären APIView verwenden, müssen Sie die eigene Paginator-Klasse von Django verwenden. 

Django Paginierung in Ansichten

In Ihrem Fall können Sie Queryset paginieren, bevor Sie es an den Serializer senden.

Etwas wie das:

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)

Hoffe das hilft.

12
Aakash Rayate

Während die Erwähnung von rayy eine Möglichkeit ist, kann Django-rest-Framework intern mit einigen zusätzlichen Funktionen umgehen, die die Arbeit mit Ihrer API wesentlich erleichtern. (* Anmerkung: Die Paginierung des Django-Rest-Frameworks wurde vom Django-Paginator aus Django.core.paginator erstellt.)

Gleich nach dem, was Sie zitiert haben, sind die wichtigsten Informationen zur Lösung dieses Problems:

Die Paginierung wird nur automatisch durchgeführt, wenn Sie die generischen Ansichten oder Ansichten verwenden. Wenn Sie einen regulären APIView verwenden, müssen Sie die Paginierungs-API selbst aufrufen, um sicherzustellen, dass Sie eine paginierte Antwort zurückgeben. Der Quellcode für die Klassen mixins.ListMixin und generics.GenericAPIView enthält ein Beispiel.

Leichte Korrektur gegenüber dem, was dort steht: Schauen Sie sich das ListModelMixin an.

Wenn Sie zu diesen beiden Links gehen, können Sie den Quellcode für die oben genannten Dateien sehen: generics.pymixins.py

Was Sie tun müssen, ist Folgendes wie das Folgende, damit die Paginierung in APIView funktioniert (** Hinweis: Dieser Code wurde nicht getestet, aber die Idee ist richtig. Es gibt auch eine bessere Möglichkeit, dies zu schreiben, als den Code einzufügen In jeder Hinsicht werde ich das aber Ihnen überlassen, um meine Antwort kurz und verständlich zu halten):

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)

Ich hoffe, dies war für Sie und andere, die auf diesen Beitrag stoßen, mehr Hilfe.

21
prawg

Ich verwende die DRF-Version 3.6.2. Sie müssen nicht so viel codieren. Verwenden Sie einfach diese einfachen Schritte. 

 class ProductPagination(PageNumberPagination):
        page_size = 5

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

wenn Sie die Suchfunktion durch Abrufen der Methode erhalten möchten, können Sie den folgenden Code eingeben

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
Nids Barthwal

Ich ziehe es vor, die Paginator-Klasse zu erweitern, so würde es aussehen:

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
NFern