DRF APIView自定义分页如何处理EmptyPage异常返回合法响应
DRF 分页 EmptyPage 异常处理方案
PageNumberPagination 触发EmptyPage报错的原因是:用户传入的页码值大于分页总页数时,底层Django分页器找不到对应页数据直接抛出异常,没有做兜底处理。以下两种方案都可以解决问题,优先选第一种,侵入性最低。
方案1:重写自定义分页类逻辑(推荐)
直接修改你现有CustomPagination类的paginate_queryset方法,在分页逻辑里直接捕获异常做兜底,不需要修改任何视图、Mixin代码,所有用这个分页类的接口自动生效。
from rest_framework import pagination from django.core.paginator import EmptyPage, PageNotAnInteger class CustomPagination(pagination.PageNumberPagination): page_size = 10 page_size_query_param = 'page_size' max_page_size = 10 page_query_param = 'p' def paginate_queryset(self, queryset, request, view=None): page_num = request.query_params.get(self.page_query_param, 1) page_size = self.get_page_size(request) paginator = self.django_paginator_class(queryset, page_size) total_pages = paginator.num_pages try: self.page = paginator.page(page_num) except PageNotAnInteger: # 传入的页码不是整数时,默认返回第一页 self.page = paginator.page(1) except EmptyPage: # 页码超出范围时的兜底逻辑,二选一即可 # 选项1:自动返回最后一页的有效数据 self.page = paginator.page(total_pages) # 选项2:返回空结果集,和正常分页结构保持一致 # self.page = paginator.page(1) # self.page.object_list = self.page.object_list.none() self.request = request if paginator.num_pages > 1 and self.template is not None: self.display_page_controls = True return list(self.page)
改完之后,不管请求传p=999这种超出范围的页码,还是传非数字的页码值,都不会抛出500错误,返回的响应结构和正常分页完全一致,前端不需要额外适配异常格式。
方案2:全局异常统一拦截
如果项目里有多个分页类,不想逐个修改,可以通过DRF全局异常处理器统一捕获分页相关异常,所有接口自动生效。
- 先写自定义异常处理函数:
from rest_framework.views import exception_handler from rest_framework.response import Response from rest_framework import status from django.core.paginator import EmptyPage, PageNotAnInteger def global_exception_handler(exc, context): # 先走DRF默认的异常处理逻辑 resp = exception_handler(exc, context) # 单独处理分页类异常 if isinstance(exc, (EmptyPage, PageNotAnInteger)): # 响应内容、状态码可以根据前后端约定调整 return Response( { "count": 0, "next": None, "previous": None, "results": [], "msg": "请求页码无效" }, status=status.HTTP_200_OK ) return resp
- 在项目
settings.py的DRF配置里注册这个异常处理器:
REST_FRAMEWORK = { # 你原有的其他DRF配置... 'EXCEPTION_HANDLER': '你的项目代码目录路径.global_exception_handler', }
补充说明
你现有的PaginationHandlerMixin和视图类代码不需要做任何修改,上面两种方案都可以直接兼容。如果只有单个接口需要特殊处理页码异常,也可以直接在视图的get方法里用try/except包裹paginate_queryset调用做单独处理,不过这种方式会产生重复代码,不推荐大规模使用。
内容的提问来源于stack exchange,提问作者Hossein Gholami
相关产品推荐
相关产品推荐

