我们在浏览很多网页的时候,由于数据太多,很多时候不能放在一个页面上,此时就需要分页功能。比如我们看到的博客园最下面的分页栏,它是动态的显示的,比如虽然说总页数会是100页,但我们不能把100页都显示出来,始终显示当前页的前5页和后5页,然后还有首页、尾页、上一页、下一页等功能,今天我就来实现这一功能,我们可以把它封装成一个类,以后哪里需要了,直接引用就行了。
一、把分页功能定义成一个类
pagination.py
class Pagination(object):
def __init__(self,current_page,all_count,request,one_count=10,one_pages=11):
self.current_page=current_page #这是当前页
self.all_count=all_count #这是数据的总数量
self.request=request
self.one_count=one_count #这是一页能展示的数据量
self.one_pages=one_pages #这是一页能放几个页码
self.mid_num=(one_pages-1)/2 #这是当前页码前后可以有几个页码数
if all_count%one_count==0:
self.pages=all_count//one_count #这是总页码数
else:
self.pages=all_count//one_count+1
@property
def start(self): #这是拿到这一页数据的开头数
return (self.current_page-1)*self.one_count
@property
def end(self): #这是拿到这一页数据的结尾数
if self.current_page==self.pages:
return self.all_count
return self.current_page*self.one_count
def get_page(self): #这是当前页真正展示的页码及每个页码的路径,在这一步,用到了保留上次请求数据的技术,使得我们跳到其他页码后,搜索条件等请求数据依然保留,返回的是一个列表,里面放的就是展示页码的前端代码
content=copy.deepcopy(self.request.GET) #对于request.GET是不允许修改,但当我们深拷贝之后,就可以,content是这次请求进来后的请求数据
data_list=[]
if self.pages <= self.one_pages: #这是当数据的总页码数小于每一个页可以显示的页码数时,我们的页码就没必要动态变化了,直接让所有页码显示出来就行了
first_page=1 #所以,页码开始数为1
last_page=self.pages #页码结束数为总页码数
else: #这是总页码数大于一页能显示的页码数时,就需要动态的显示页码,一般情况下
if self.current_page<=self.mid_num: #当当前页码的前面页码数小于我们设定的当前页码前要显示的页码数时,比如我们设定的mid_num为5,但我现在是第3页,前面没有5个页码
first_page=1 #页码开始数为1
last_page=self.one_pages #页码结束数为一页能显示的页码数
elif self.current_page+self.mid_num>self.pages: #总页码为20,当前页码为18,mid_num为5,但后面不够5个页码
last_page=self.pages #页码结束数为总的页码数
first_page=self.pages-self.one_pages+1 #开始数为总页码数减去一页能显示的页码数
else: #这是前后都够mid_num=5个页码的
first_page=self.current_page-self.mid_num #开始数为当前页码数减去mid_num
last_page=self.current_page+self.mid_num #结束数为当前页码数加上mid_num
#上一页和首页
content['page']=1 #首页就是page为1的,我们把请求数据的page改为1
data_list.append(mark_safe('<nav aria-label="Page navigation" style="position: absolute;bottom: 20px;left:0;right:0;text-align: center" >'
'<ul class="pagination"><li><a href="?%s" aria-label="Previous"><span aria-hidden="true">首页</span></a></li>'%content.urlencode()))
if self.current_page==1: #这是上一页,把page改为当前页码数减1,但当现在页码为1时,上一个就没有设置值
data1=mark_safe('<li class="disabled"><span aria-hidden="true">上一页</span></li>')
else:
content['page']=self.current_page-1
data1=mark_safe('<li><a href="?%s" aria-label="Previous"><span aria-hidden="true">上一页</span></a></li>'%(content.urlencode()))
data_list.append(data1)
for i in range(int(first_page),int(last_page+1)): #从页码开始数到结束数循环,给每一个页码加上前端代码,和请求路径,把page改为当前循环的页码数
content['page']=i
if i==self.current_page:
data_list.append('<li><li class="active"><a href="?%s">%s</a></li></li>'%(content.urlencode(),i))
else:
data_list.append('<li><li><a href="?%s">%s</a></li></li>' % (content.urlencode(), i))
#下一页和尾页,
if self.current_page==self.pages: #和上一页、首页 一样
data2=mark_safe('<li class="disabled"><span aria-hidden="true">下一页</span></li>')
else:
content['page']=self.current_page+1
data2=mark_safe('<li><a href="?%s" aria-label="Next"><span aria-hidden="true">下一页</span></a></li>'%(content.urlencode()))
data_list.append(data2)
content['page']=self.pages
data_list.append(mark_safe('<li><a href="?%s" aria-label="Previous"><span aria-hidden="true">尾页</span></a></li></ul></nav>'%content.urlencode()))
data=''.join(data_list) #最好把列表里面的所有标签用空格连起来,返回,前端拿到这个标签字符,直接用模板渲染就行了
return mark_safe(data)
现在有一个页面上需要用到分页,去调用这个类。
test.py
from pagination import Pagination
def show(request):
pagination = Pagination(current_page,queryset.count(), request, one_count=2, one_pages=9) #我们要传当前的页数,数据的总数,,一页可以展示的数据数,一页的页码数
data_page = pagination.get_page() #这是已经写好的页码的前端代码
obj_list = queryset[pagination.start:pagination.end] #这是得到这一页要展示的数据
return render(request,'show.html',locals())
show.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/bootstrap.css">
<script class="lazy" data-src="/static/jquery-3.3.1.js"></script>
<script class="lazy" data-src="/static/js/bootstrap.js"></script>
</head>
<body>
<div>{{obj_list}}</div> #这是要展示的数据,格式还需要调整,循环这个列表,拿到每个对象,然后再取每个对象的值,用标签渲染
{{ data_page }} #这是写好的页码代码,直接放在这里,就可以拿到页码
</body>
</html>
展示效果,只需看最下面的页码,上面的数据,我是用标签渲染过的