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})

浙公网安备 33010602011771号