django EmptyPage错误

一、问题简介
在使用django的分页功能时,发现页码超出范围抛出EmptyPage错误,但是我已经知道get_page()方法是会自动处理页码问题的,所以就很纳闷, 一度怀疑是django的bug,经过一系列的排查,终于确定了问题,先说结论: get_elided_page_range(). 是这个方法导致的问题,不是get_page()的问题
二、排查过程

我开始以为是get_page()的问题,一心想找出是不是这个方法出bug了。后面用debug调试发现并不是它的问题,而是get_elided_page_range()方法的问题,查看了它的源码发现这里也会抛出EmptyPage的错误,下面是源码,可以看到number=self.validate_number(number)它也调用了这个函数验证数据,但是坑的是它没有捕获处理异常,而get_page是处理了的,源码如下所示,所以这个异常会一直往外抛直到被django捕获报错,这就是问题的原因。

难受的是我修改时又出现了问题,我的想法是既然这里往外抛异常,那我在自己的函数中捕获这个异常不就行了啊,代码如下,但是却不行,因为get_elided_page_range这个方法是个生成器,不调用结果的时候是无法触发异常的,只有在前端循环获取这个页码列表时才会触发错误,这时已经迟了,try except 捕获的位置没用了(这里折腾了很久,还是因为对python基础不牢啊)

# 自己最开始的分页代码
def archive_list(request, page_num):
    # params_orm_map,前端传参和orm字段映射
    params_orm_map = {
        'archive_name': 'archive_name__contains',
        'table': 'table',
        'archive_owner': 'archive_owner'
    }

    # 把存在的参数放入参数字典中
    params_dict = {}
    for key, value in params_orm_map.items():
        if request.GET.get(key):
            params_dict[value] = request.GET.get(key)
    # 查询
    archive_queryset = Archiver.objects.filter(**params_dict).order_by('-create_time')

    # 分页
    paginator = Paginator(archive_queryset, 6)
    page_obj = paginator.get_page(page_num)
    page_num_range = paginator.get_elided_page_range(page_num, on_each_side=1, on_ends=1)
    return render(request, 'op_tool/archive_list.html', {'page_obj': page_obj, 'page_num_range': page_num_range})


# get_elided_page_range方法源码
def get_elided_page_range(self, number=1, *, on_each_side=3, on_ends=2):
    
    number = self.validate_number(number)

    if self.num_pages <= (on_each_side + on_ends) * 2:
        yield from self.page_range
        return

    if number > (1 + on_each_side + on_ends) + 1:
        yield from range(1, on_ends + 1)
        yield self.ELLIPSIS
        yield from range(number - on_each_side, number + 1)
    else:
        yield from range(1, number + 1)

    if number < (self.num_pages - on_each_side - on_ends) - 1:
        yield from range(number + 1, number + on_each_side + 1)
        yield self.ELLIPSIS
        yield from range(self.num_pages - on_ends + 1, self.num_pages + 1)
    else:
        yield from range(number + 1, self.num_pages + 1)

# get_page方法源码
def get_page(self, number):
    # 可以看到对validate_number这个方法抛出的异常进行处理了
    try:
        number = self.validate_number(number)
    except PageNotAnInteger:
        number = 1
    except EmptyPage:
        number = self.num_pages
    return self.page(number)

# 自己代码里捕获异常的代码部分
paginator = Paginator(archive_queryset, 6)
page_obj = paginator.get_page(page_num)

try:
    page_num_range = paginator.get_elided_page_range(page_num, on_each_side=1, on_ends=1)
except EmptyPage:
    page_num_range = paginator.get_elided_page_range(paginator.num_pages, on_each_side=1, on_ends=1)

return render(request, 'op_tool/archive_list.html', {'page_obj': page_obj, 'page_num_range': page_num_range})


三、解决办法
# 解决办法有两个,
# 一是自己手动在对这个传进来的页码进行判断处理下,代码如下:
    # 分页
    paginator = Paginator(archive_queryset, 6)
    page_obj = paginator.get_page(page_num)
    # 确保页码在有效范围内,get_elided_page_range方法如果超出页码范围会报空页的错误
    if page_num < 1:
        page_num = 1
    elif page_num > paginator.num_pages and paginator.num_pages > 0:
        page_num = paginator.num_pages
    page_num_range = paginator.get_elided_page_range(page_num, on_each_side=1, on_ends=1)

    return render(request, 'op_tool/archive_list.html', {'page_obj': page_obj, 'page_num_range': page_num_range})


# 二是使用get_page处理后的页码
    # 分页
    paginator = Paginator(archive_queryset, 6)
    page_obj = paginator.get_page(page_num)
    # 这里传入的是page_obj.number,这个是经过上面get_page处理过的正常页码了
    page_num_range = paginator.get_elided_page_range(page_obj.number, on_each_side=1, on_ends=1)

    return render(request, 'op_tool/archive_list.html', {'page_obj': page_obj, 'page_num_range': page_num_range})

posted @ 2025-12-10 16:47  有形无形  阅读(12)  评论(0)    收藏  举报