Django Rest 框架 - APIView 分页

Posted

技术标签:

【中文标题】Django Rest 框架 - APIView 分页【英文标题】:Django Rest Framework - APIView Pagination 【发布时间】:2016-06-20 05:43:01 【问题描述】:

我有一个非常简单的APIView,但我不知道如何在这里设置分页。 在这种情况下,我选择一个带有给定pkEvent,然后我将所有NewsItems 分配给这个Event

pagination_class = LimitOffsetPaginationListCreateAPIView 开头定义查询集时工作正常,例如。 queryset = Event.objects.all() 但不是自定义get

class EventNewsItems(APIView):
    pagination_class = LimitOffsetPagination

    def get(self, request, pk, format=None):

        #user = request.user
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

        serializer = NewsItemSerializer(news, many=True, context='request':request)
        response = Response(serializer.data, status=status.HTTP_200_OK)
        return response

已解决:

def get(self, request, pk, format=None):

    #user = request.user
    event = Event.objects.get(pk=pk)
    news = event.get_news_items().all()
    paginator = LimitOffsetPagination()
    result_page = paginator.paginate_queryset(news, request)
    serializer = NewsItemSerializer(result_page, many=True, context='request':request)
    response = Response(serializer.data, status=status.HTTP_200_OK)
    return response

【问题讨论】:

查看这个讨论,看起来这家伙解决了你的问题github.com/tomchristie/django-rest-framework/issues/3030 嘿,@user3128673 我想知道我的回答是否有帮助。 【参考方案1】:

另一个选项是从分页类继承,对视图类的更改更少:

from rest_framework.pagination import LimitOffsetPagination

class EventNewsItems(APIView, LimitOffsetPagination):

    def get(self, request, pk, format=None):
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

        results = self.paginate_queryset(news, request, view=self)
        serializer = NewsItemSerializer(results, many=True)
        return self.get_paginated_response(serializer.data)

【讨论】:

谢谢你!有没有办法在每个视图的基础上设置默认限制和偏移量? 彼得保罗的回答让我的评论过时了 最佳解决方案! @FelixPK 您可以在 settings.py 中设置默认的 PAGE_SIZE 并使用 limitoffset 查询参数。【参考方案2】:

我已经为此主题创建了Q&A style example。 作为排序摘要:

通过利用 Django Rest Frameworks 源代码以及它们如何处理分页,我们在视图类中创建相同的方法并使用它们,就像您的解决方案使用默认方法一样:

取自上述文档:

from rest_framework.settings import api_settings
from rest_framework.views import APIView

class MyView(APIView):
    queryset = OurModel.objects.all()
    serializer_class = OurModelSerializer
    pagination_class = api_settings.DEFAULT_PAGINATION_CLASS # cool trick right? :)

    # We need to override get method to achieve pagination
    def get(self, request):
        ...
        page = self.paginate_queryset(self.queryset)
        if page is not None:
            serializer = self.serializer_class(page, many=True)
            return self.get_paginated_response(serializer.data)

        ... Do other stuff needed (out of scope of pagination)

    # Now add the pagination handlers taken from 
    #  django-rest-framework/rest_framework/generics.py

    @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) 

【讨论】:

self._paginator = self.pagination_class(). TypeError: 'list' object is not callable - 我收到此错误。 缩进有点偏离 @GiannisKatsini 确实(我想我已经修复了所有问题)您可以随意编辑您看到的任何内容。【参考方案3】:

另一种分页方法是使用 Paginator 类。

除了答案查询,还必须设置要显示的页数和页面将包含的元素范围。

页码和项目范围可以作为请求参数的一部分提供,也可以通过您选择的方式提供。

以问题的情况为例:

from django.core.paginator import Paginator

class EventNewsItems(APIView):

    def get(self, request, pk, format=None):

        #user = request.user
        event = Event.objects.get(pk=pk)
        news = event.get_news_items().all()

         # -----------------------------------------------------------
        page_number = self.request.query_params.get('page_number ', 1)
        page_size = self.request.query_params.get('page_size ', 10)

        paginator = Paginator(news , page_size)
        serializer = NewsItemSerializer(paginator.page(page_number) , many=True, context='request':request)
        # -----------------------------------------------------------

        response = Response(serializer.data, status=status.HTTP_200_OK)
        return response

【讨论】:

如果您想在每次观看的基础上处理限制和偏移,那就太好了! 如果您请求的页面为空,您将收到异常。您将需要处理django.core.paginator.EmptyPage 异常

以上是关于Django Rest 框架 - APIView 分页的主要内容,如果未能解决你的问题,请参考以下文章

python Django Rest_Framework框架 APIView介绍与序列化器详解(图文并茂版)

python Django Rest_Framework框架 APIView介绍与序列化器详解(图文并茂版)

将 APIView 添加到 Django REST Framework 可浏览 API [重复]

即使我使用了 ScrapyItem.objects.all(),我在 django rest 框架的 APIView 内的 post 方法中也只得到一个对象。任何人都知道为啥

python Django Rest_Framework框架 两个视图基类详解(图文并茂版)

python Django Rest_Framework框架 两个视图基类详解(图文并茂版)