Python Django rest framework全局分页参数不适用于ModelViewSet

Python Django rest framework全局分页参数不适用于ModelViewSet,python,django,pagination,django-rest-framework,Python,Django,Pagination,Django Rest Framework,DRF文件规定: 仅当使用常规视图或视图集时,才会自动执行分页 但是我使用的是从ViewSet继承的ModelViewSet,所以我告诉自己“很酷,我所要做的就是将它添加到我的设置中。py”: 然而,这并没有起作用。 如果我发送27个项目的GET请求,它将返回所有项目(在可浏览的API和json中) 我认为我应该只被送回12个月,对吗 子问题:PAGE_SIZE是每页返回的顶级对象数,对吗?我看到了一些使用PAGINATE_BY的示例,但是 没有功能,所以我认为它不推荐 我使用的是DRF3.

DRF文件规定:

仅当使用常规视图或视图集时,才会自动执行分页

但是我使用的是从
ViewSet
继承的
ModelViewSet
,所以我告诉自己“很酷,我所要做的就是将它添加到我的
设置中。py
”:

然而,这并没有起作用。
如果我发送27个项目的GET请求,它将返回所有项目(在可浏览的API和json中)

  • 我认为我应该只被送回12个月,对吗
  • 子问题:PAGE_SIZE是每页返回的顶级对象数,对吗?我看到了一些使用
    PAGINATE_BY
    的示例,但是 没有功能,所以我认为它不推荐
我使用的是DRF3.6.3,Django1.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,
}
我还在
ModelViewSet
类中添加了
pagination\u class=PageNumberPagination
,但没有效果

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

>>> from rest_framework.pagination import PageNumberPagination
>>> p = PageNumberPagination()
>>> p.max_page_size
>>> print(p.page_size)
12
它应该会起作用。 如果没有,并且您没有输入错误,请查看服务器日志,您可能会发现一些信息告诉您,没有顺序的分页将不起作用:

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

为了解决这个问题,请确保在模型的元中指定一个顺序,或者在
ModelViewSet
queryset
中设置
order\u,尽管从
GenericViewSet
ListMixin
继承,但默认情况下,分页在
ModelViewSet
上不起作用。您需要手动添加它:

我编写了一个解决该问题的程序,并在
ModelViewSet
类上对其进行了测试

我将略作总结:

  • 创建自定义mixin以利用分页类
  • 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)
    
  • 使您的视图集扩展该mixin并覆盖
    ModelViewSet
    list()
    方法:

    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...
    
  • 当然,您需要根据自己的需要校准此解决方案,但这将为
    ModelViewSet
    添加分页



    对于这个子问题,@Linovia的评论是正确的,
    PAGINATE\u BY
    已被弃用,
    PAGE\u SIZE
    是响应页面大小的当前设置。

    PAGINATE\u BY是设置页面大小的前一种方法(),我有一个无序的查询集,但从框架的角度来看,我认为这并不重要。我现在已经点了,但没什么变化。我已经在原来的问题中添加了更多的调试信息,但是我还没有解决为什么一些设置(分页、渲染器)看起来没有被选中。
    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...