Django DRF 分页

文章目录

    • 1. 分页器
    • 2. PageNumberPagination
    • 3. LimitOffsetPagination
    • 4. CursorPagination
    • 5. 自定义基于 APIView 实现分页

1. 分页器

REST framework提供了分页的支持,内置的分页器需要继承 GenericAPIView 和 ListModelMixin,对查询所有接口进行分页。

2. PageNumberPagination


1. 可以自己继承 PageNumberPagination 设置属性,如下示例

  • 分页类
from rest_framework.pagination import PageNumberPagination

class CommonPageNumberPagination(PageNumberPagination):
    page_size = 3
    page_size_query_param = 'size'
    max_page_size = 5
    page_query_param = 'page'
属性 解释
page_size 每页数目
page_query_param 前端发送的页数关键字名,默认为”page”
page_size_query_param 前端发送的每页数目关键字名,默认为None
max_page_size 前端最多能设置的每页数量
  • 视图函数

只要在视图函数中添加以下配置

pagination_class = CommonPageNumberPagination

如果在视图内关闭分页功能,只需在视图内设置

pagination_class = None
  • 路由
http://127.0.0.1:8000/students/?page=2&size=30		# 使用 GET 方法  

在路由中添加的 page 表示页码,size 表示一页展示的条数


2. 也可以直接在 setting 配置文件中全局添加,如下所示

  • 配置文件
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS':  'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 100  # 每页数目
}

3. LimitOffsetPagination

1. 方法一,继承 LimitOffsetPagination 定义属性

  • 分页类
class CommonLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2  
    limit_query_param = 'limit' 
    offset_query_param = 'offset'  
    max_limit = 5  
属性 解释
default_limit 默认展示条数,默认值与 PAGE_SIZE 设置一致
limit_query_param limit 参数名,默认 ’limit’,控制取的条数
offset_query_param offset 参数名,默认 ’offset’。控制从第 X 个位置偏移多少开始取数据
max_limit 最大limit限制,默认 None
  • 视图函数

只要在视图函数中添加以下配置

pagination_class = CommonLimitOffsetPagination

如果在视图内关闭分页功能,只需在视图内设置

pagination_class = None
  • 路由
http://127.0.0.1:8000/students/?limit=2&offset=3		# 使用 GET 方法  

在路由中添加的 limit 表示一个页码展示的取出条数,offset 表示偏移数。例如上面的路由是每页展示 2 条数据,并且是从第 3 条数据开始展示 2 条,也就是展示的是 第 4、5 条数据。

4. CursorPagination

1. 方法一,继承 CursorPagination定义属性

  • 分页类
class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  
    page_size = 3 
    ordering = 'id'  
属性 解释
cursor_query_param 默认查询字段,类似于 cursor = xxx,但是该值是随机的。
page_size 每页展示的数目
ordering 按什么排序,一般使用 id,需要注意其必须是表中有的字段
  • 视图函数

只要在视图函数中添加以下配置

pagination_class = CommonCursorPagination

如果在视图内关闭分页功能,只需在视图内设置

pagination_class = None

5. 自定义基于 APIView 实现分页

前面的使用内置分页的视图函数都需要继承 GenericAPIView、ListModelMixin,我们可以自己编写继承 APIView 的视图函数实现分页。

  • 视图函数(前提准备好内置的分页器)
class MyPage(APIView):
    def get(self, request):
    	# 获取所有数据集
        books = models.Book.objects.all()
        
        # 对数据集进行分页,可以是自己配置了参数的分页器
        paginator = CommonPageNumberPagination()
        
        # 获取分页过后的数据
        qs = paginator.paginate_queryset(books, request, self)
        
        # 对数据进行序列化,多条数据需要添加 many=True
        res = serializer.BookSerializer(qs, many=True)

		# 返回的方式一,只返回分页后的结果
        # return Response(res.data)

		# 返回方式二,自己配置返回的其他信息,例如上一页下一页
        # return Response({
        #     'count': books.count(),
        #     'next': paginator.get_next_link(),
        #     'previous': paginator.get_previous_link(),
        #     'results': res.data
        # })

		# 返回方式三,使用方法自动返回类似于方式二的内容
        return paginator.get_paginated_response(res.data)
        
  • 路由
    和普通继承了 APIView 的视图函数一样配置路由。
    如果我们需要自动配置路由,我们可以先继承 ViewSet,有三种方式添加。
1.	path('mypage/', BookViews.MyPage.as_view({'get': 'get'})),
2.	
	from django.urls import path
	from app01.view import BookViews
	from rest_framework.routers import SimpleRouter
	
	router = SimpleRouter()
	router.register('mypage', BookViews.MyPage, 'mypage')
	
	urlpatterns = []
	urlpatterns += router.urls

3. 添加 @action(methods=['get',], detail=False)

这么编写的方式可以查看源码解析。

源码解析

  • ListModelMixin 源码
class ListModelMixin:
    """
    List a queryset.
    """
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        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)
        
  1. 查看 ListModelMixin 源码发现其调用了 self.paginate_queryset(queryset) 方法,而该方法并没有在拓展类中,而在 GenericAPIView 中会有该方法。

  • GenericAPIView 源码
def paginate_queryset(self, queryset):
    if self.paginator is None:
        return None
    return self.paginator.paginate_queryset(queryset, self.request, view=self)
  1. 在 GenericAPIView 的 paginate_queryset 方法中的 paginator 调用了 paginate_queryset 方法。
  2. paginator 其实是一个方法当作属性调用,如下所示,其取了我们配置的分页器类
@property
def paginator(self):
    if not hasattr(self, '_paginator'):
        if self.pagination_class is None:
            self._paginator = None
        else:
            self._paginator = self.pagination_class()
    return self._paginator
  1. paginate_queryset 方法也就是分页器类的方法,传入 queryset, self.request, view=self 参数,得到的结果就是分页过后的数据。
  2. 然后对数据进行序列化即可。除了序列化分页的结果,还可以配置例如数据集的长度等。其有一个方法配置了返回的样式,源码如下,我们仿照配置即可,或者直接调用该方法。
def get_paginated_response(self, data):
    return Response(OrderedDict([
        ('count', self.page.paginator.count),
        ('next', self.get_next_link()),
        ('previous', self.get_previous_link()),
        ('results', data)
    ]))

你可能感兴趣的:(Django,框架,django,python,后端)