You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django中如何无需转列表用PageNumberPagination分页RawQuerySet

在Django中实现RawQuerySet的PageNumber分页(无需全量转列表)

要解决RawQuerySet无法直接使用PageNumberPagination的问题,核心是补充分页所需的总记录数计算和惰性切片逻辑,以下是具体实现方案:

自定义兼容RawQuerySet的分页类

继承DRF的PageNumberPagination,重写分页逻辑以适配RawQuerySet:

from rest_framework.pagination import PageNumberPagination
from django.db import connection

class RawQuerySetPagination(PageNumberPagination):
    page_size = 15
    page_query_param = 'page'

    def paginate_queryset(self, queryset, request, view=None):
        # 1. 高效计算总记录数(避免全量加载)
        # 基于原始SQL生成count查询,封装为子查询
        count_sql = f"SELECT COUNT(*) FROM ({queryset.raw_query}) AS sub_query"
        with connection.cursor() as cursor:
            cursor.execute(count_sql)
            total_count = cursor.fetchone()[0]
        
        # 初始化分页器的总数和总页数属性
        self.paginator.count = total_count
        self.paginator.num_pages = (total_count + self.page_size - 1) // self.page_size

        # 2. 解析当前页码,计算偏移量
        page_num = request.query_params.get(self.page_query_param, 1)
        try:
            page_num = max(int(page_num), 1)
        except ValueError:
            page_num = 1
        
        offset = (page_num - 1) * self.page_size
        end_offset = offset + self.page_size

        # 3. 对RawQuerySet进行惰性切片(仅加载当前页数据)
        paginated_data = queryset[offset:end_offset]

        # 设置分页上下文
        self.page = self.paginator.page(page_num)
        self.request = request
        return list(paginated_data)

在视图中使用自定义分页类

替换原代码中的分页逻辑,使用自定义类处理RawQuerySet:

# 视图中的示例代码
queryset = CheckTraModelTotal.objects.raw(sql_query)
paginator = RawQuerySetPagination()
page_data = paginator.paginate_queryset(queryset, self.request)
serializer = self.get_serializer(page_data, many=True)
return paginator.get_paginated_response(serializer.data)

关键注意事项

  • 禁止用len(queryset)计算总数:这会触发全量SQL查询并加载所有数据到内存,严重影响性能。必须用原生count子查询实现高效计数。
  • RawQuerySet切片是惰性的:queryset[offset:end_offset]会自动在原始SQL后拼接LIMIT/OFFSET,仅查询当前页数据,无需全量转换为列表。
  • 清理原始SQL中的LIMIT/OFFSET:如果你的sql_query已经包含分页相关语句,需要先移除,避免和分页器的逻辑冲突。

内容的提问来源于stack exchange,提问作者Abdul Rahman.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:53:32