Django分页

分页的目的是:在数据量太大分批获取数据并在页面上进行展示

简单的操作就是通过切片获取

1
2
user_list = models.UserInfo.objects.all()[1:10]
user_list = models.UserInfo.objects.all()[10:20]

Django自带分页

适合做上下页,只能在Django中用

分页操作实现

首先导入对象Paginator

from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage

在浏览器中通过GET发送当前的页码,后面加上?page=1

http://127.0.0.1:8000/index.html?page=1

python后台代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def index(request):
"""
Djangon内置的分页,实现的功能是上下页
:param request:
:return:
"""
# 通过GET方式获取当前页码
current_page = request.GET.get('page')
user_list = models.UserInfo.objects.all() # 获取全部的用户数据
# user_list = models.UserInfo.objects.all().count() # 获取具体的数据量
# print(user_list)
# user_list = models.UserInfo.objects.all()[0:10] # 通过切片的方式获取数据
paginator = Paginator(user_list, 10) # (第一参数object_list,第二个参数per_age)
# 下面是paginator的方法
# per_page: 每页显示条目数量
# count: 数据总个数
# num_pages:总页数
# page_range:总页数的索引范围,如: (1,10),(1,200)
# page: 返回值是一个对象
posts = paginator.page(current_page) # 传入的是页码的值
# 下面是posts的方法
# has_next 是否有下一页
# next_page_number 下一页页码
# has_previous 是否有上一页
# previous_page_number 上一页页码
# object_list 分页之后的数据列表
# number 当前页
# paginator paginator对象
return render(request, 'index.html', {'posts': posts})

前端代码,通过posts拿到分页后的数据,上下页之前先判断是否有上一页或者下一页,之后拼接路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<h1>django内置的分页</h1>
<ul>
{% for row in posts.object_list %} {# object_list是分页之后的数据列表 #}
<li>{{ row.name }}</li>
{% endfor %}
</ul>
<div>
{% if posts.has_previous %}
<a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
{% endif %}
{% if posts.has_next %} {# 判断有下一页的时候 #}
<a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
{% endif %}
</div>

关于URL中的问题

在URL中只能接收的是int型的数字,如果传入的是字母,会报错PageNotAnInteger at /index.html,在后台进行异常处理,捕捉异常之后的操作是返回到第一页。

在URL中传入的是负数的话,报错EmptyPage at /index.html,处理同样是返回到第一页

已经在前面导入了异常处理的
from django.core.paginator import Paginator,Page,PageNotAnInteger,EmptyPage

1
2
3
4
5
6
7
8
try:
posts = paginator.page(current_page) # 传入的是页码的值
# except PageNotAnInteger as e:
# posts = paginator.page(1)
# except EmptyPage as e:
# posts = paginator.page(1)
except Exception as e:
posts = paginator.page(1) # 异常处理 返回第一页

Django的页码

Django的页码在数据量很大的时候,会显示所有的分页的页码,比如有300条数据,每页显示10条数据,就会有30个页码。所以需要进行自己开发

在index的上下页中间添加,post下有paginator方法,paginator下有page_range 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
<div>
{% if posts.has_previous %}
<a href="/index.html?page={{ posts.previous_page_number }}">上一页</a>
{% endif %}
{% for num in posts.paginator.page_range %} {# post下有paginator,paginator下有page_range #}
<a href="/index.html?page={{ num }}">{{ num }}</a>
{% endfor %}
{% if posts.has_next %} {# 判断有下一页的时候 #}
<a href="/index.html?page={{ posts.next_page_number }}">下一页</a>
{% endif %}
</div>

总结:
Django的分页适用于上下翻页的情况,不适合中间的页码,如果数据量太大,不适合

自定义分页

可以在任何地方使用,以后封装成一个类

最原始的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def custom(request):
# 用户当前要访问的页码
current_page = request.GET.get('page')
current_page = int(current_page) # 强制转换成整型
# 每页显示的个数
per_page = 10
# 1 1:10 最后一个取不到
# 2 10:20
# 3 20:30
start = (current_page - 1) * per_page # 数据库的索引是从0开始的
end = current_page * per_page
user_list = models.UserInfo.objects.all()[start:end]
return render(request, 'custom.html', {"user_list": user_list})

把页码的计算封装成类

注意类中的参数传值的时候要一一对应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
class PageInfo(object):
def __init__(self, current_page, all_count, per_page, ):
try:
self.current_page = int(current_page)
except Exception as e:
current_page = 1 # url 没找到的时候跳转到第一页
self.per_page = per_page
a, b = divmod(all_count, per_page) # 通过divmod进行分页,有余数的再加一页
if b:
a += 1 # 有余数的时候页码加1
self.all_page = a # all_page 是总的页码
def start(self):
return (self.current_page - 1) * self.per_page
def end(self):
return self.current_page * self.per_page
def pager(self):
# v = "<a href='/custom.html?page=1'>1</a>" # 双引号中中用单引号
# return v
# 显示所有的页码
page_list = []
for i in range(1, self.all_page + 1):
if i == self.current_page:
# 判断是当前页的时候,加上背景色
# temp = "<a style='padding=5px display=inl' href='/custom.html?page=%s'>%s</a>" %(i,i) # 选中的加背景色
temp = "<a style='display: inline-block;padding: 5px;margin: 5px;background-color: red' href='/custom.html?page=%s'>%s</a>" % (
i, i)
else:
temp = "<a style='display: inline-block;padding: 5px;margin: 5px' href='/custom.html?page=%s'>%s</a>" % (
i, i)
page_list.append(temp)
return ''.join(page_list) # 把列表中的值取出并拼接成字符串
# 自定义分页
def custom(request):
# 用户当前要访问的页码
# current_page = request.GET.get('page')
# page_info = PageInfo(current_page,10)
all_count = models.UserInfo.objects.all().count()
page_info = PageInfo(request.GET.get('page'), all_count, 10)
user_list = models.UserInfo.objects.all()[page_info.start():page_info.end()] # 对象继承类的方法
return render(request, 'custom.html', {"user_list": user_list, 'page_info': page_info})

继续优化成页码的显示方式

这种是定义了固定的显示页面数11(当前页和前后5页),现在的问题是两端的极限值的问题

左边必须是当前页>=6
右边的问题是会查不到数据后还显示页码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class PageInfo(object):
def __init__(self, current_page, all_count, per_page, show_page=11):
try:
self.current_page = int(current_page)
except Exception as e:
current_page = 1 # url 不是
self.per_page = per_page
a, b = divmod(all_count, per_page) # 通过divmod进行分页,有余数的再加一页
if b:
a += 1
self.all_page = a # all_page 是总的页码
self.show_page = show_page
def start(self):
return (self.current_page - 1) * self.per_page
def end(self):
return self.current_page * self.per_page
def pager(self):
# v = "<a href='/custom.html?page=1'>1</a>" # 双引号中中用单引号
# return v
half = int((self.show_page-1)/2)
begin = self.current_page - half
stop =self.current_page +half +1
# 显示所有的页码
page_list = []
for i in range(begin,stop):
if i == self.current_page:
# 判断是当前页的时候,加上背景色
# temp = "<a style='padding=5px display=inl' href='/custom.html?page=%s'>%s</a>" %(i,i) # 选中的加背景色
temp = "<a style='display: inline-block;padding: 5px;margin: 5px;background-color: red' href='/custom.html?page=%s'>%s</a>" % (
i, i)
else:
temp = "<a style='display: inline-block;padding: 5px;margin: 5px' href='/custom.html?page=%s'>%s</a>" % (
i, i)
page_list.append(temp)
return ''.join(page_list) # 把列表中的值取出并拼接成字符串

优化右边的极限

1
2

把页面制作成一个插件

放到utils文件夹中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
class PageInfo(object):
def __init__(self, current_page, all_count, per_page, base_url, show_page=11):
"""
:param current_page:
:param all_count: 数据库总行数
:param per_page: 每页显示函数
:return:
"""
try:
self.current_page = int(current_page)
except Exception as e:
self.current_page = 1
self.per_page = per_page
a, b = divmod(all_count, per_page)
if b:
a = a + 1
self.all_pager = a
self.show_page = show_page
self.base_url = base_url
def start(self):
return (self.current_page-1) * self.per_page
def end(self):
return self.current_page * self.per_page
def pager(self):
# v = "<a href='/custom.html?page=1'>1</a><a href='/custom.html?page=2'>2</a>"
# return v
page_list = []
half = int((self.show_page-1)/2)
# 如果数据总页数 < 11
if self.all_pager < self.show_page:
begin = 1
stop = self.all_pager + 1
# 如果数据总页数 > 11
else:
# 如果当前页 <=5,永远显示1,11
if self.current_page <= half:
begin = 1
stop = self.show_page + 1
else:
if self.current_page + half > self.all_pager:
begin = self.all_pager - self.show_page + 1
stop = self.all_pager + 1
else:
begin = self.current_page - half
stop = self.current_page + half + 1
if self.current_page <= 1:
prev = "<li><a href='#'>上一页</a></li>"
else:
prev = "<li><a href='%s?page=%s'>上一页</a></li>" % (
self.base_url, self.current_page-1,)
page_list.append(prev)
for i in range(begin, stop):
if i == self.current_page:
temp = "<li class='active'><a href='%s?page=%s'>%s</a></li>" % (
self.base_url, i, i,)
else:
temp = "<li><a href='%s?page=%s'>%s</a></li>" % (
self.base_url, i, i,)
page_list.append(temp)
if self.current_page >= self.all_pager:
nex = "<li><a href='#'>下一页</a></li>"
else:
nex = "<li><a href='%s?page=%s'>下一页</a></li>" % (
self.base_url, self.current_page+1,)
page_list.append(nex)
return ''.join(page_list)

使用

1
2
3
4
5
6
7
8
9
10
11
12
from utils.pager import PageInfo
def custom(request):
# 表示用户当前想要访问的页码: 8
all_count = models.UserInfo.objects.all().count()
page_info = PageInfo(request.GET.get(
'page'), all_count, 10, '/custom.html', 11)
user_list = models.UserInfo.objects.all(
)[page_info.start():page_info.end()]
return render(request, 'custom.html', {'user_list': user_list, 'page_info': page_info})

前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7-dist/css/bootstrap.css" />
</head>
<body>
<h1>用户列表</h1>
<ul>
{% for row in user_list %}
<li>{{ row.name }}</li>
{% endfor %}
</ul>
<nav aria-label="Page navigation">
<ul class="pagination">
{{ page_info.pager|safe }}
</ul>
</nav>
</body>
</html>

© 2018 Peter's Blog Center All Rights Reserved.
Theme by hiero