Разбиение на страницы в 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