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

DRF APIView无Model、Serializer场景下自定义分页响应实现方法咨询

解决方案

最优方案:SQL层面分页(彻底解决内存溢出问题)

该方案的核心逻辑是将分页逻辑下沉到数据库查询层面,每次仅加载当前页的数据到内存中,从根本上避免全量数据加载导致的OOM问题,完全适配你当前的原生SQL+Pandas+DRF的技术栈,不需要引入Model或Serializer。

第一步:自定义DRF分页器

你可以直接继承DRF自带的分页基类,不需要依赖序列化器或模型,按需配置分页规则即可:

from rest_framework.pagination import PageNumberPagination

class CustomPagination(PageNumberPagination):
    # 默认每页返回10条数据
    page_size = 10
    # 允许前端通过page_size参数自定义每页条数
    page_size_query_param = 'page_size'
    # 限制每页最大返回条数,避免异常请求占用过多资源
    max_page_size = 100

第二步:修改视图逻辑实现SQL分页

需要对原生SQL做两处扩展:先查询总数据量用于生成分页元数据,再给原SQL增加分页限制查询当前页数据:

class AffiliateAPIView(APIView):
    permission_classes = (IsAuthenticated,)  
    pagination_class = CustomPagination

    def get(self, request):
        insurance = self.request.query_params.get('insurance', None)
        base_sql = general_attention(insurance)
        paginator = self.pagination_class()

        # 读取分页参数
        page = int(request.query_params.get(paginator.page_query_param, 1))
        page_size = int(request.query_params.get(paginator.page_size_query_param, paginator.page_size))
        page_size = min(page_size, paginator.max_page_size)
        offset = (page - 1) * page_size

        # 查询总数据量
        count_sql = f"SELECT COUNT(*) as total FROM ({base_sql}) AS temp_total"
        total_count = pd.read_sql(count_sql, engine()).iloc[0]['total']
        paginator.page.paginator.count = total_count

        # 仅查询当前页数据
        paginated_sql = f"{base_sql} LIMIT %s OFFSET %s"
        page_df = pd.read_sql(paginated_sql, engine(), params=(page_size, offset))
        page_data = page_df.to_dict(orient='records')

        # 返回标准分页格式响应,包含总条数、上下页链接、当前页数据
        return paginator.get_paginated_response(page_data)

临时方案:Pandas内存切片(仅适合小数据量场景)

如果你的数据量较小,暂时不想修改SQL逻辑,可以直接对全量加载后的DataFrame做内存切片分页。注意:该方案仍然会加载全量数据到内存中,无法解决大数据量下的内存溢出问题,仅可作为临时过渡方案:

class AffiliateAPIView(APIView):
    permission_classes = (IsAuthenticated,)  
    pagination_class = CustomPagination

    def get(self, request):
        insurance = self.request.query_params.get('insurance', None)
        emergensys_df = pd.read_sql_query(general_attention(insurance), engine())
        paginator = self.pagination_class()
        page = paginator.paginate_queryset(emergensys_df.to_dict(orient='records'), request, view=self)
        return paginator.get_paginated_response(page)

注意事项

  • 使用SQL层面分页时,建议给你的原生SQL加上固定的排序规则(比如按主键、创建时间排序),避免分页结果出现重复、遗漏数据的问题
  • 上述分页SQL语法适配MySQL、PostgreSQL数据库,如果你使用的是Oracle等其他数据库,需要对应调整分页语法(Oracle使用ROWNUM实现分页)
  • 若你的原生SQL包含用户传入的动态参数,不要直接做字符串拼接,使用pd.read_sql的params参数传递动态值,避免SQL注入风险
  • 可以根据业务需求调整CustomPagination中的page_size、max_page_size等配置参数

内容的提问来源于stack exchange,提问作者Anthony

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 04:18:02