Разбиение на страницы в Django-Rest-Framework с использованием API-View

В настоящее время у меня есть настройка представления API следующим образом:

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)

Здесь CartDetailSerializer - обычный ModelSerializer.

Я хочу разбивать страницы на этот API. Однако в документах DRF я нашел следующее:

Если вы используете обычный APIView, вам нужно позвонить в API разбиения на страницы, чтобы убедиться, что вы возвращаете постраничный ответ.

Нет примера о том, как развернуть регулярный API APIView.

Может ли кто-нибудь опубликовать пример, который я могу использовать в приведенном выше сценарии.

Спасибо.

Ответ 1

При использовании обычного APIView вам нужно использовать собственный класс Paginator Django.

Django Pagination in Views

В вашем случае вы можете разбивать запрос на запрос перед отправкой его в сериализатор.

Что-то вроде этого:

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)

Надеюсь, что это поможет.

Ответ 2

В то время как упоминание о лучах возможно, django-rest-framework может справиться с этим внутренне с некоторыми дополнительными функциями, которые значительно упрощают работу с вашим API. (* note django-rest-framework pagination построена из paginator Django из django.core.paginator)

Сразу после того, что вы указали, является ключевой информацией для решения этой проблемы:

Разметка выполняется только автоматически, если вы используете общие представления или виды. Если вы используете обычный APIView, вам нужно позвонить в API разбиения на страницы, чтобы убедиться, что вы возвращаете постраничный ответ. См. исходный код классов mixins.ListMixin и generics.GenericAPIView для примера.

Небольшая коррекция на то, что указано там: посмотрите на ListModelMixin.

Если вы перейдете к этим двум ссылкам, вы можете увидеть исходный код для вышеуказанных файлов: generics.py mixins.py

Что вам нужно сделать, так это включить в APIView что-то вроде следующего, чтобы получить разбиение на страницы (примечание **: этот код непроверен, но идея верна. Также есть лучший способ написать это, а не иметь включите код во все виды, но я оставлю это до вас, чтобы мой ответ был коротким и понятным):

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)

Я надеюсь, что это помогло вам и другим, кто попадает на этот пост.

Ответ 3

Я использую версию DRF 3.6.2. Вам не нужно кодировать так много. Просто используйте эти простые шаги.

 class ProductPagination(PageNumberPagination):
        page_size = 5

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

если вы хотите использовать функцию поиска, получив метод, вы можете написать ниже код

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