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
相关产品推荐
相关产品推荐

