分页最麻烦的应该是计算省略号部分,并且很多人不明白到底前端分页还是后端分页,本人页尝试过很多方法,但整个过程和计算是真的太麻烦,看着脑壳疼,想着更疼
经过很多探索和尝试后,发现Django3.2版本新增一个get_elided_page_range()方法,这个就是后端为我们分页后并得到两边的省略号对象,官方文档如下
具体用法:
后端
1.创建一个文件:Pagination.py,以后所有的分页都可以调用它。
2.在Pagination.py编写一个新的Custom_Paginator(obj, page, page_size)
#引入Django自带的Paginator
from django.core.paginator import Paginator
def Custom_Paginator(obj, page, page_size):
#将接收到的obj变量按照page_size分页
paginator = Paginator(obj, page_size)
#得到当前page的数据列表
page_of_obj = paginator.get_page(page)
#上一页
has_previous = page_of_obj.has_previous()
#下一页
has_next = page_of_obj.has_next()
#当前页码
current_page_num = page_of_obj.number
#总页数
total_page = paginator.num_pages # 总页数
#数据记录总数
count = paginator.count
#这里判断左右两边的页码小于最小页数或大于最大页数
if current_page_num - 1 <= 0:
prevous_page_num = 1
else:
prevous_page_num = current_page_num - 1
if current_page_num + 1 >= total_page:
next_page_num = total_page
else:
next_page_num = current_page_num + 1
#重点!!!这里判断两遍的省略号,用get_elided_page_range()方法,给它提供当前页码
page_range = list(paginator.get_elided_page_range(number=page))
if current_page_num * page_size - page_size == 0:
current_start_num = 1
else:
current_start_num = current_page_num * page_size - page_size
if current_page_num * page_size > count:
current_end_num = count
else:
current_end_num = current_page_num * page_size
#封装一下数据
data = {
#注意这里得到的当前页码的数据列表是QuerySet,不能直接返回前端,会报错
#还需要拿到data后简单转换一下
'objects_list': page_of_obj,
'has_previous': has_previous,
'has_next': has_next,
'page_range': page_range,
'elided': page_of_obj.paginator.ELLIPSIS,
'current_page_num': current_page_num,
'prevous_page_num': prevous_page_num,
'next_page_num': next_page_num,
'current_start_num': current_start_num,
'current_end_num': current_end_num,
'total_page': total_page,
'count': count,
}
return data
3.拿到数据后, 编写View.py
#引入刚刚写的方法
From .Pagination import Custom_Paginator
class get_obj_list(APIView):
def get(self, request):
page = int(request.GET.get('page', 1))
page_size = 30
#查找数据
list = User.objects.filter(company_code=company_code).order_by('create_time')
data = Custom_Paginator(list, page, page_size)
#得到的data,增加一个被转换的json数据
data['obj_list'] = objSerializer(instance=data['objects_list'], many=True).data
#把原来分页得到的QuerySet删除
del data['objects_list']
#这里返回数据,就不报错了
return JsonResponse(data, json_dumps_params={'ensure_ascii': False}, safe=False)
前端
1.用一个div来放置分页数据,id=‘pages'
<ul id="pages" class="pagination mb-sm-0">
...这里用js写入刚刚拿到的数据
</ul>
2. 从ajax拿到数据后,编写一个html内容,需要append到<ul>标签
#每次都清空一下重新写入
$('#pages').html('')
#设置pages变量为空
var pages = ''
#下方所有判断和循环,都用+=写入到pages变量
#判断最前面的箭头,是否还有上一页,没有的话就不能点击
if ( data.has_previous ){
var previous = data.prevous_page_num
pages += '<li class="page-item"><a href="javascript:void(0)" onclick="'+func+'(' + previous + ')" class="page-link"><i class="mdi mdi-chevron-left"></i></a></li>'
}
else {
pages += '<li class="page-item"><a class="disabled page-link"><i class="mdi mdi-chevron-left"></i></a></li>'
}
#判断当前页和中间部分
var page_range = data.page_range
var current_page_num = data.current_page_num
var elided = data.elided
for ( i=0; i<page_range.length;i++) {
if (current_page_num == page_range[i]) {
pages += '<li class="page-item active"><a href="javascript:void(0)" class="page-link">' + page_range[i] + '</a></li>'
}
else if ( page_range[i] == elided ) {
pages += '<li class="page-item"><a class="page-link">' + '...' + '</a></li>'
}
else {
pages += '<li class="page-item"><a href="javascript:void(0)" onclick="'+func+"(" + page_range[i] + ')" class="page-link">' + page_range[i] + '</a></li>'
}
}
#判断最后面的箭头,是否还有下一页,没有的话就不能点击
if ( data.has_next ){
var next = data.next_page_num
pages += '<li class="page-item"><a href="javascript:void(0)" onclick="'+func+"(" + next + ')" class="page-link"><i class="mdi mdi-chevron-right"></i></a></li>'
}else {
pages += '<li class="page-item"><a class="disabled page-link"><i class="mdi mdi-chevron-right"></i></a></li>'
}
#最后把pages变量写入标签
$('#pages').html(pages)
3.效果
可以根据不同的点击页数动态显示所有页数和省略号,也大大提高查询速度
这一套代码可以用在django开发的任何需要分页的位置,更精细的玩法,可以分开不同的查询去分页而互不影响。有兴趣的朋友可以共同探讨