如何在非通用视图/视图集中使用分页?

时间:2017-08-14 08:46:10

标签: python django pagination django-rest-framework

序言

我在多个帖子中看到了这个问题:

也可以在这里应用:

我已经在SO文档中编写了一个示例,以便在上述问题中统一我的答案,但由于文档将于2017年8月8日关闭,我将遵循this widely upvoted and discussed meta answer的建议并将我的示例转换为自我回答了帖子。

当然,我也很高兴看到任何不同的方法!!

问题:

我想在Django Rest Framework项目中使用非通用视图/视图集(例如:APIView)。
正如我在pagination documentation上看到的那样:

  

只有在使用通用视图或视图集时,才会自动执行分页。如果您使用常规APIView,则需要自行调用分页API以确保返回分页响应。有关示例,请参阅mixins.ListModelMixingenerics.GenericAPIView类的源代码。

我还可以继续使用非通用视图/视图集吗? 我怎样才能实现分页?

1 个答案:

答案 0 :(得分:10)

我们可以找到一个解决方案,而无需重新发明轮子:

  1. 让我们看一下generics分页的实现方式: django-rest-framework/rest_framework/generics.py
    这正是我们将要用于我们观点的内容!

  2. 我们假设我们有一个如下所示的全局分页设置:
    settings.py

    REST_FRAMEWORK = {
        'DEFAULT_PAGINATION_CLASS': 
            'rest_framework.pagination.DESIRED_PAGINATION_STYLE',
        'PAGE_SIZE': 100
    }
    
  3. 为了不膨胀我们的视图/视图集的代码,我们可以创建一个自定义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)
    
  4. 然后在views.py

    from rest_framework.settings import api_settings
    from rest_framework.views import APIView
    
    from my_app.mixins import MyPaginationMixin
    
    class MyView(APIView, MyPaginationMixin):
        queryset = OurModel.objects.all()
        serializer_class = OurModelSerializer
        pagination_class = api_settings.DEFAULT_PAGINATION_CLASS 
    
        # We need to override the get method to insert 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)
    
  5. 现在我们有一个APIView的分页。