1、目的&环境准备
目的:把分页用模块方式实现,然后在需要分页的地方直接调用模块。
环境准备:创建一个Django项目,并从中生成一个App,注册之后配置urls&Models。
配置Urls
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include("pages.urls")),
]
from django.conf.urls import url
from pages import views
urlpatterns = [
url(r'^user_list/', views.user_list),
]
注册App
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pages',
]
配置Models
from django.db import models
# Create your models here.
class UserList(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
2、分析&完善代码
分页功能基本上大部分网站中都是需要的,比如豆瓣话题小组的分页,当我们查看的时候他有很多话题讨论块,而它也不是一下子把所有的话题都返回给我们,它实现如下图的分页来推送博文让我们浏览:
而我们可以根据页面按钮来点击前页和后页或者点击我们想要查看的页面,然后显示我们要查看的话题块和链接!而不是一下把所有内容都给我们显示出来,这样做的好处就是即可以节省流量又能够改善用户的体验。
那么我们要实现这样的功能,首先要同步表结构生成数据库,之后创建数据(500条即可)。
配置简单Views创建基础数据
from django.shortcuts import render
from django.shortcuts import HttpResponse
from pages import models
# Create your views here.
def user_list(request):
for i in range(500):
dic = {'username': 'name_%d' % i, 'age': i}
models.UserList.objects.create(**dic)
return HttpResponse('OK')
创建模板,配置Html显示数据并通过Views获取数据显示
Pages Models
{% for line in result %}
{{ line.username }}
{{ line.age }}
{% endfor %}
{{ pager_str|safe }}
修改Views
def user_list(request):
result = models.UserList.objects.all()
return render(request,'page_list.html',{'result':result})
这样,前端就可以正常显示初始的500条数据了。但是我需要每页显示固定的数据量,所以我需要先获取页数,然后配置Urls,直接通过配置正则,用参数获取页面传过来的值。
from django.conf.urls import url
from pages import views
urlpatterns = [
url(r'^user_list/', views.user_list),
url(r'^user_list/(?P\d+)/$', views.user_list),
]
def user_list(request):
current_page = request.GET.get('page')
print current_page
result = models.UserList.objects.all()[0:10] # 每页显示10条信息
return render(request,'page_list.html',{'result':result})
然后通过修改Views让页面开始和结束,即start & end 动态起来。
def user_list(request):
current_page = request.GET.get('page',1)
current_page = int(current_page)
start = (current_page-1)*10 #10 20 (current_page-1)*10
end = current_page*10 #20 30 current_page*10
result = models.UserList.objects.all()[start:end]
return render(request,'page_list.html',{'result':result})
然后封装整理Views到类和函数便于调用
from django.shortcuts import render
from django.shortcuts import HttpResponse
from pages import models
# Create your views here.
class Pager(object):
def __init__(self,current_page):
self.current_page = int(current_page)
#把方法伪造成属性(1)
@property
def start(self):
return (self.current_page-1)*10
@property
def end(self):
return self.current_page*10
def user_list(request):
current_page = request.GET.get('page',1)
page_obj = Pager(current_page)
#把方法改造成属性(2),这样在下面调用方法的时候就不需要加括号了
result = models.UserList.objects.all()[page_obj.start:page_obj.end]
return render(request,'page_list.html',{'result':result})
以上代码是通过修改浏览器url实现了分页,现在我需要生成前后页和页数按钮来点击实现分页。那么为了实现具体的效果,我们也得考虑最后页如果数据超出怎么办?也就是说要通过divmod(500,10)来判断它最后页是否有余数,是否是10条数据形成整页,如果有余数的话,我们让其在整页基础加1即可以实现,即在后端生成一个大的字符串然后把它返回给前端。
配置Views
from django.shortcuts import render
from django.shortcuts import HttpResponse
from pages import models
# Create your views here.
class Pager(object):
def __init__(self,current_page):
self.current_page = int(current_page)
#把方法伪造成属性(1)
@property
def start(self):
return (self.current_page-1)*10
@property
def end(self):
return self.current_page*10
def user_list(request):
current_page = request.GET.get('page',1)
page_obj = Pager(current_page)
#吧方法未造成属性(2),这样在下面调用方法的时候就不需要加括号了
result = models.UserList.objects.all()[page_obj.start:page_obj.end]
all_item = models.UserList.objects.all().count()
all_page,div = divmod(all_item,10)
if div > 0:
all_page +=1
pager_str = ""
for i in range(1,all_page+1):
#每次循环生成一个标签
temp = '%d' %(i,i,)
#把标签拼接然后返回给前端
pager_str += temp
return render(request,'page_list.html',{'result':result,'pager_str':pager_str})
配置前端页面page_list.html
Title
{% for line in result %}
{{ line.username }}
{{ line.age }}
{% endfor %}
{{ pager_str|safe }}
{{ page_str | safe }} 这样写是因为Django为了防止XSS攻击产生而设置的机制,这个和我们之前学过一个CSRF跨站请求伪造的安全设置差不多。
接下来我需要配置Views让页码动态起来保持显示固定页数。
from django.shortcuts import render
from django.shortcuts import HttpResponse
from pages import models
# Create your views here.
class Pager(object):
def __init__(self,current_page):
self.current_page = int(current_page)
#把方法伪造成属性(1)
@property
def start(self):
return (self.current_page-1)*10
@property
def end(self):
return self.current_page*10
def page_str(self,all_item,base_url):
all_page, div = divmod(all_item, 10)
if div > 0:
all_page += 1
pager_str = ""
# #默认可以看到的页码11个
#
# start = self.current_page - 5
# end = self.current_page + 6
#
# #把页面动态起来传入起始和结束
# for i in range(start, end):
#
# #判断是否为当前页
# if i == self.current_page:
# temp = '%d' % (base_url,i,i)
# else:
# temp = '%d' % (base_url,i,i)
#
# # 把标签拼接然后返回给前端
# pager_str += temp
if all_page <= 11:
start = 1
end = all_page
else:
if self.current_page <= 6:
start = 1
end = 11 + 1
else:
start = self.current_page - 5
end = self.current_page + 6
if self.current_page + 6 > all_page:
start = all_page - 10
end = all_page + 1
#把页面动态起来传入起始和结束
for i in range(start, end):
#判断是否为当前页
if i == self.current_page:
temp = '%d' % (base_url,i,i)
else:
temp = '%d' % (base_url,i,i)
# 把标签拼接然后返回给前端
pager_str += temp
return pager_str
def user_list(request):
current_page = request.GET.get('page',1)
page_obj = Pager(current_page)
#把方法改造成属性(2),这样在下面调用方法的时候就不需要加括号了
result = models.UserList.objects.all()[page_obj.start:page_obj.end]
all_item = models.UserList.objects.all().count()
pager_str = page_obj.page_str(all_item,'/user_list/')
return render(request,'page_list.html',{'result':result,'pager_str':pager_str})
现在简单自定义分页就完成了,然后可以再给他增加一个“上一页” & 下一页
我们也可以把他给为一个列表,然后每次生成的标签append到列表中,然后分别在列表中最前面和后面增加,上一页和下一页
from django.http import HttpResponse
from django.shortcuts import render
from pages import models
class Pager(object):
def __init__(self, current_page):
self.current_page = int(current_page)
# 把方法伪造成属性(1)
@property
def start(self):
return (self.current_page - 1) * 10
@property
def end(self):
return self.current_page * 10
def page_str(self, all_item, base_url):
all_page, div = divmod(all_item, 10)
if div > 0:
all_page += 1
pager_list = []
# # 默认可以看到的页码11个
#
# start = self.current_page - 5
# end = self.current_page + 6
#
# # 把页面动态起来传入起始和结束
# for i in range(start, end):
#
# # 判断是否为当前页
# if i == self.current_page:
# temp = '%d' % (base_url,i,i)
# else:
# temp = '%d' % (base_url,i,i)
#
# # 把标签拼接然后返回给前端
# pager_str += temp
if all_page <= 11:
start = 1
end = all_page
else:
if self.current_page <= 6:
start = 1
end = 11 + 1
else:
start = self.current_page - 5
end = self.current_page + 6
if self.current_page + 6 > all_page:
start = all_page - 10
end = all_page + 1
# 把页面动态起来传入起始和结束
for i in range(start, end):
# 判断是否为当前页
if i == self.current_page:
temp = '%d' % (base_url, i, i)
else:
temp = '%d' % (base_url, i, i)
# 把标签拼接然后返回给前端
pager_list.append(temp)
# 上一页
if self.current_page > 1:
pre_page = '上一页' % (base_url, self.current_page - 1)
else:
# javascript:void(0) 什么都不干
pre_page = '上一页'
# 下一页
if self.current_page >= all_page:
next_page = '下一页'
else:
next_page = '下一页' % (base_url, self.current_page + 1)
pager_list.insert(0, pre_page)
pager_list.append(next_page)
return "".join(pager_list)
def user_list(request):
# for i in range(500):
# dic = {'username': 'name_%d' % i, 'age': i}
# models.UserList.objects.create(**dic)
# return HttpResponse('OK')
current_page = request.GET.get('page', 1)
page_obj = Pager(current_page)
# 把方法改成属性(2), 这样在下面调用方法的时候就不需要加括号了
# print(current_page)
# current_page = int(current_page)
# start = (current_page-1)*10
# end = current_page*10
result = models.UserList.objects.all()[page_obj.start:page_obj.end]
all_item = models.UserList.objects.all().count()
pager_str = page_obj.page_str(all_item, '/user_list/')
# all_page, div = divmod(all_item, 10)
#
# if div > 0:
# all_page += 1
#
# pager_str = ""
# for i in range(1, all_page+1):
# # 每次循环生成一个标签
# temp = '%d' % (i, i,)
# # 把标签拼接然后返回给前端
# pager_str += temp
return render(request, 'page_list.html', {'result': result, 'pager_str': pager_str})
最后可以单独列出来写成模块供主项目调用,也可以把分页的数量动态化,使其更好应用在项目中!