非泛型 ViewsViewset 上的高级分页

*这是一个高级主题,如果没有先了解此页面的其他示例,请不要尝试*。

正如关于分页的官方 Django Rest Framework中所述 :

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

但是如果我们想在非通用视图/视图集上使用分页呢?

好吧,让我们走下兔子洞吧:

  1. 第一站是官方的 Django Rest Framework 的存储库,特别是 django-rest-framework / rest_framework / generics.py 。这个链接指向的特定行向我们展示了框架的开发人员如何处理其泛型中的分页。
    这正是我们将要用于我们观点的内容!

  2. 让我们假设我们有一个全局分页设置,如本页介绍示例中所示,并假设我们有一个我们想要应用分页的 APIView

  3. 然后在 views.py

    from django.conf import settings
    from rest_framework.views import APIView
        
    class MyView(APIView):
        queryset = OurModel.objects.all()
        serializer_class = OurModelSerializer
        pagination_class = 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)
    

现在我们有一个处理分页的 APIView