Django休息框架全局分页参数不适用于ModelViewSet

时间:2017-06-23 13:06:48

标签: python django pagination django-rest-framework

DRF文档指出:

  

只有在您使用通用视图或视图集时才会自动执行分页。

但我使用的ModelViewSet继承自ViewSet,所以我告诉自己"很酷,我所要做的就是将其添加到我的settings.py ":

'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 12, # for 12-col grid css frameworks

然而,这并没有奏效 如果我发送了27个项目的GET请求,则返回所有这些项目(在可浏览的API和json中)。

  • 我是否正确地认为我应该只返回12?
  • 子问题: PAGE_SIZE是每页返回的顶级对象的数量,对吧?我看到了一些PAGINATE_BY的例子 the source中没有功能,所以我认为它已被弃用?

我正在使用DRF 3.6.3,django 1.11.2。

修改:我的设置:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ),
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 12,
}

我还在pagination_class = PageNumberPagination课程中添加了ModelViewSet,但没有效果。

以下是来自shell的验证,Pagination类确实知道它应该提供的页面大小:

>>> from rest_framework.pagination import PageNumberPagination
>>> p = PageNumberPagination()
>>> p.max_page_size
>>> print(p.page_size)
12

2 个答案:

答案 0 :(得分:1)

它应该工作。 如果它没有并且您没有输入错误,请查看服务器日志,您可能会发现一些信息告诉您没有订单的分页将无效:

xxxx/django/core/paginator.py:112: UnorderedObjectListWarning: Pagination may yield inconsistent results with an unordered object_list: ....

为了解决这个问题,请确保在模型的Meta中指定排序,或在order_by ModelViewSet {/ 1}内设置queryset

答案 1 :(得分:1)

尽管从ModelViewSetGenericViewSet继承,但ListMixin默认情况下,分页默认不起作用。您需要手动添加它:

我已经编写了Q&A style example来解决这个问题,并在ModelViewSet课程上进行了测试。

我将总结一下:

  1. 创建自定义mixin以使用pagination_class

    class MyPaginationMixin(object):
        @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)
    
  2. 使您的视图集扩展该mixin并覆盖list()的{​​{1}}方法:

    ModelViewSet
  3. 您需要根据自己的需要校准此解决方案,但这会为class MyViewset(MyPaginationMixin, viewsets.ModelViewSet): # since you are setting pagination on the settings, use this: pagination_class = settings.DEFAULT_PAGINATION_CLASS def list(self, request, *args, **kwargs): response = dict( super(MyViewSet, self).list(self, *args, **kwargs).data) page = self.paginate_queryset(response['results']) if page is not None: serializer = self.serializer_class(page, many=True) return self.get_paginated_response(serializer.data) else: # Something went wrong here... 添加分页。

    对于子问题,@ Linovia的评论是正确的,ModelViewSet已被弃用,PAGINATE_BY是响应页面大小的当前设置。