Django Rest Framework 使用 PageNumberPagination 类添加页码属性

Posted

技术标签:

【中文标题】Django Rest Framework 使用 PageNumberPagination 类添加页码属性【英文标题】:Django Rest Framework add page number attribute using the PageNumberPagination class 【发布时间】:2018-03-19 12:21:17 【问题描述】:

我正在使用 Django 和 Django rest 框架构建一个 API,并且我正在尝试在 json 结果中添加页码。我正在尝试在返回的结果中添加页码,例如,我目前正在获取此信息;


  "links": 
    "next": null,
    "previous": null
  ,
  "count": 1,
  "results": [
    
      "url": "http://127.0.0.1:8000/api/brands/1/?format=json",
      "name": "microsoft",
      "description": "Nothing",
      "top_brand": true,
      "guid": "microsoft"
    
  ]

但我想得到这样的东西;


  "count": 1,
  "results": [
    
      "url": "http://127.0.0.1:8000/api/brands/1/?format=json",
      "name": "microsoft",
      "description": "Nothing",
      "top_brand": true,
      "guid": "microsoft"
    ,
    ...
  ],
  "page_number": 1,
  "from": 1,
  "to": 10,
  "last_page": 4

最重要的属性是 page_number,但我不太确定如何使用 self... 从父类中获取它,除了使用函数之外,我看不到直接的方法。这是我的代码;

class StandardResultsSetPagination(PageNumberPagination):
    page_size = 100
    page_size_query_param = 'page_size'
    max_page_size = 1000

    def get_paginated_response(self, data):
        return Response(
            'links': 
                'next': self.get_next_link(),
                'previous': self.get_previous_link()
            ,
            'count': self.page.paginator.count,
            'results': data,
            'page_number': self.page.paginator...,
        )

【问题讨论】:

【参考方案1】:

您可以在视图集中使用自定义分页并在自定义视图上进行更改

pagination.py

class CustomPageNumber(pagination.PageNumberPagination):
    page_size = 2

    def get_paginated_response(self, data):
        return Response(OrderedDict([
             ('lastPage', self.page.paginator.count),
             ('countItemsOnPage', self.page_size),
             ('current', self.page.number),
             ('next', self.get_next_link()),
             ('previous', self.get_previous_link()),
             ('results', data)
         ]))

在你看来

class TestViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Test.objects.all().order_by('-created_at')
    serializer_class = TestSerializer

    @list_route(methods=['get'], url_path='get-records/(?P<pk>[^/]+)')
    def get_record(self, request, pk):
        self.pagination_class = CustomPageNumber
        queryset = self.filter_queryset(self.queryset.filter(course=pk))
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data) 

你需要在你的 settings.py 中配置

REST_FRAMEWORK = 
    'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPageNumber',
    'PAGE_SIZE': 100

如果您想了解更多信息,请参阅文档custom-pagination-class

【讨论】:

这里 def get_paginated_response 的响应中有一个错误...响应“ last_page : self.page.paginator.count ”没有给出总页数...它会给你总记录,这将获取。 最好改用("countItemsOnPage", self.get_page_size(self.request))。如果查询包含像 &amp;page_size=5 这样的 page_size 参数,则应反映在响应中,而不是始终反映在 2 我偶然发现了这个,试图在我的分页中获取当前页面和最后一页。这确实有效,但只有一个小问题。最后一页实际上并没有得到最后一页。为了做到这一点,我刚刚做了 last_page = math.ceil(self.page.paginator.count / self.page_size) 然后在 Response ('last_page', last_page), 。希望这对某人有所帮助。【参考方案2】:

如果我理解你是正确的,你可以使用self.page.number

    return Response(
        'links': 
            'next': self.get_next_link(),
            'previous': self.get_previous_link()
        ,
        'count': self.page.paginator.count,
        'results': data,
        'page_number': self.page.number,
        #              ^^^^^^^^^^^^^^^^
    )

【讨论】:

【参考方案3】:

我相信像这样获得tofrom 可能更适用:

class MyCustomPagination(pagination.PageNumberPagination):

    def get_from(self):
        return int((self.page.paginator.per_page * self.page.number) - self.page.paginator.per_page + 1)

    def get_to(self):
        return self.get_from() + int(len(self.page.object_list)) - 1

    def get_paginated_response(self, data):

        return Response(
            'next': self.get_next_link(),
            'previous': self.get_previous_link(),
            'count': self.page.paginator.count,
            'total_pages': self.page.paginator.num_pages,
            'page_number': self.page.number,
            'per_page': self.page.paginator.per_page,
            'from': self.get_from(),
            'to': self.get_to(),
            'results': data
        )

【讨论】:

【参考方案4】:

自从回答了这个问题后,就有一个新组件采用 :number-of-pages 属性。

https://bootstrap-vue.org/docs/components/pagination-nav

【讨论】:

【参考方案5】:

在您的回复中显示当前页码 基本上你可以在你的views.py文件上做到这一点 通过创建一个自定义的“pagination_class”,如下所示。

我有模型调用“评论”, 注意:这只是示例,请根据您的要求进行更改:

## view all comments with Custom paganation ##
class MyCustomPagination(PageNumberPagination):
    page_size = 1
    page_size_query_param = 'page_size'
    def get_paginated_response(self, data):
        return Response(
            'count': self.page.paginator.count,
            'page_number': self.page.number,
            'next': self.get_next_link(),
            'previous': self.get_previous_link(),
            'results': data,
        )




class C_ApiCommentListView(ListAPIView):
    queryset = Comment.objects.all()
    serializer_class = App1CommentSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)
    pagination_class = MyCustomPagination
    filter_backends = (SearchFilter, OrderingFilter)
    search_fields = ('COM_comment', 'COM_title', 'COM_user__username')

我希望这对你有帮助。

【讨论】:

以上是关于Django Rest Framework 使用 PageNumberPagination 类添加页码属性的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest Framework 和 django Rest Framework simplejwt 两因素身份验证

18-Django REST framework-使用Django开发REST 接口

如何在 django-rest-framework 中为 API 使用 TokenAuthentication

Django-rest-framework 和 django-rest-framework-jwt APIViews and validation Authorization headers

django rest framework中文介绍

使用 django-rest-framework-simplejwt 注册后返回令牌