自定义分页(模块化)
自定义分页
1、目的&环境准备
目的把分页写成一个模块的方式然后在需要分页的地方直接调用模块就行了。
环境准备Django中生成一个APP并且注册,配置URL&Views
配置URL
from django.conf.urls import url from django.contrib import admin from app01 import viewsurlpatterns = [url(r'^admin/', admin.site.urls),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','app01', ]
配置models
from __future__ import unicode_literalsfrom django.db import models# Create your models here.class UserList(models.Model):username = models.CharField(max_length=32)age = models.IntegerField()
2、分析
分页在基本上行所有的大型网站中都是需要的,比如博客园的分页,当我们查询的时候或查看的时候他有很多博文,难道他是一下把所有的博文都给我们返回的吗?当然不是:如下图
我们可以根据提示来点击上一页和下一页或者点击我们想要查看的页面,然后显示我们要查看的博文链接!而不是一下把所有的博文给显示出来,这样即节省流量又能改善用户体验。
3、逐步完善分页代码
首先咱们先创建500条数据(之前不要忘记生成数据库),在第一访问时设置下就OK
3.1、配置views创建数据
#/usr/bin/env python #-*- coding:utf-8 -*-from django.shortcuts import render from django.shortcuts import HttpResponse 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')
3.2、配置html显示数据并通过views获取数据显示
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><table>{% for line in result %}<tr><td>{{ line.username }}</td><td>{{ line.age }}</td></tr>{% endfor %}</table><div>{{ pager_str|safe }}</div></body></html>
views
def user_list(request):result = models.UserList.objects.all()return render(request,'user_list.html',{'result':result})
这样,前端可以正常显示咱们去的数据了,但是一下子把所有的数据都取出来了。不是咱们想要的结果。
3.3、取指定的条数
比如我想取前10条怎么取呢?
def user_list(request):result = models.UserList.objects.all()[0:10]return render(request,'user_list.html',{'result':result})
那我让[0:10]动态起来就可以了!开始和结尾。
3.4、每页显示10条数据
向用户获取页数,我们可以配置URL在URL中有两种方式查询直接在URL中配置正则,然后在views里可以通过参数来获取用户传过来的值,
也可以通过?a=9 &b=10 这样在Veiws函数里可以通过request.GET['a']取值了,并且可以设置默认值request.GET.get('a',0)
def user_list(request):current_page = request.GET.get('page')print current_pageresult = models.UserList.objects.all()[0:10]return render(request,'user_list.html',{'result':result})
测试:
这里的问号是通过get的方式向后端发送数据,我们也可以修改form表单中method改为GET,那么数据访问的时候就是通过GET方式向后端提交数据的,当点击form表单提交数据的时候,form里的内容会自动添加到浏览器的URL中以上面的格式!
虽然POST和GET都可以向后端提交数据但是规定:GET一般用来查询使用,POST一般用来提交修改数据使用,根据实际的情况来定!
看下面的代码:
def user_list(request):current_page = request.GET.get('page',1)print current_pagestart = 0 #10 20 (current_page-1)*10end = 10 #20 30 current_page*10result = models.UserList.objects.all()[start:end]return render(request,'user_list.html',{'result':result})
我们现在让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)*10end = current_page*10 #20 30 current_page*10result = models.UserList.objects.all()[start:end]return render(request,'user_list.html',{'result':result})
然后打开网页测试下,修改page的值来看下显示效果:
http://127.0.0.1:8000/user_list/?page=2
http://127.0.0.1:8000/user_list/?page=3
http://127.0.0.1:8000/user_list/?page=4
分页代码整理
我们通过把上面的代码整理一下整理到函数或类里下次使用的时候直接调用类或者函数即可。
#/usr/bin/env python #-*- coding:utf-8 -*-from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here.class Pager(object):def __init__(self,current_page):self.current_page = int(current_page)#把方法伪造成属性(1) @propertydef start(self):return (self.current_page-1)*10@propertydef end(self):return self.current_page*10def 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,'user_list.html',{'result':result})
2、生成按钮页
上面的功能实现了分页现在,我们是不是可以在下面生成一堆的按钮来让用户点击,而不是在浏览器中输入!
先看下如果咱们手动写的话!
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><table>{% for line in result %}<tr><td>{{ line.username }}</td><td>{{ line.age }}</td></tr>{% endfor %}</table><div><a href="/user_list/?page=1">1</a><a href="/user_list/?page=2">2</a><a href="/user_list/?page=3">3</a><a href="/user_list/?page=4">4</a><a href="/user_list/?page=5">5</a></div></body></html>
如下图:
目的是为了实现左侧的效果,但是咱们不可能手写吧?所以应该在后台创建,这个是不是就是总共有多少页?
需求分析:
每页显示10条数据
共500条数据就是50页,那有501条数据呢?是多少页是51页。
可以通过divmod(500,10),他会的到一个元组,第一个值是值,第二个值是余数,我们就通过判断他是否有余数来判断是否是整页,如果有余数在整页基础加1即可!
我们获取了所有的页数之后可以吧他返回在前端生成,但是这样我们后端做了分页之后前端是不是也做了分页操作?
我们可以在后端生成一个大字符串然后把他返回给前端(拼接的URL)
#/usr/bin/env python #-*- coding:utf-8 -*-from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here.class Pager(object):def __init__(self,current_page):self.current_page = int(current_page)#把方法伪造成属性(1) @propertydef start(self):return (self.current_page-1)*10@propertydef end(self):return self.current_page*10def 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 +=1pager_str = ""for i in range(1,all_page+1):#每次循环生成一个标签temp = '<a href="/user_list/?page=%d">%d</a>' %(i,i,)#把标签拼接然后返回给前端pager_str += tempreturn render(request,'user_list.html',{'result':result,'pager_str':pager_str})
前端配置:
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><table>{% for line in result %}<tr><td>{{ line.username }}</td><td>{{ line.age }}</td></tr>{% endfor %}</table><div>{{ pager_str }}</div></body></html>
但是有个问题如下图:
这个是什么问题导致的呢?
咱们在之前的文章学过一个CSRF跨站请求伪造的安全设置,这里还有一个值得说的安全就是XSS攻击:
XSS攻击:跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。
XSS是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。比如这些代码包括HTML代码和客户端脚本。攻击者利用XSS漏洞旁路掉访问控制——例如同源策略(same origin policy)。这种类型的漏洞由于被黑客用来编写危害性更大的网络钓鱼(Phishing)攻击而变得广为人知。对于跨站脚本攻击,黑客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而JavaScript是新型的“ShellCode”。
咱们上面看到的内容就是Django为了防止这样的情况产生而设置的机制,例子如下:
如果,写的简单的script可以被保存为HTML标签的话那么?只要有人打开这个页面都会提示一个信息,这样是不是不安全,这个是小的说的!
如果说这里是一个获取Cookie然后发送到指定服务器然后服务器可以通过cookie访问你的个人信息是不是就可怕了?!
那么怎么解决这个问题呢?可以通过模板语言的一个函数来告诉Django这个是安全的:加一个safe (在文章的后面还有一种方法在后端标记他是安全的)
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><table>{% for line in result %}<tr><td>{{ line.username }}</td><td>{{ line.age }}</td></tr>{% endfor %}</table><div>{{ pager_str|safe }}</div></body></html>
效果如下:
这样全显示出来了,不是很好,最好显示11页然后,当用户点击第6页的时候,这个6永远在中间!所以我们也要让页码动态起来!
#/usr/bin/env python #-*- coding:utf-8 -*-from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here.class Pager(object):def __init__(self,current_page):self.current_page = int(current_page)#把方法伪造成属性(1) @propertydef start(self):return (self.current_page-1)*10@propertydef end(self):return self.current_page*10def page_str(self,all_item,base_url):all_page, div = divmod(all_item, 10)if div > 0:all_page += 1pager_str = ""#默认可以看到的页码11个start = self.current_page - 5end = self.current_page + 6#把页面动态起来传入起始和结束for i in range(start, end):#判断是否为当前页if i == self.current_page:temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)else:temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)# 把标签拼接然后返回给前端pager_str += tempreturn pager_strdef 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,'user_list.html',{'result':result,'pager_str':pager_str})
前端页面不用修改了,看效果如下:
现在还是有问题的,当你现在点击1,2,3,4,5的时候因为前面没有页面就会出现负值!
并且最后一页页会出现无穷大,但是没有数据,那怎么解决呢?
''' 如果总页数 <= 11 比如9页:那么,还有必要让页码动起来吗?就没必要了直接显示总共页数就行了!start就是1,end就是9就行了 else:如果当前页小宇6:start:1end:11如果当前页大于6:start:当前页-5end:当前页+6如果当前页+6 >总页数:start:总页数-10end:总页数 '''
修改后的代码:
#/usr/bin/env python #-*- coding:utf-8 -*-from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here.class Pager(object):def __init__(self,current_page):self.current_page = int(current_page)#把方法伪造成属性(1) @propertydef start(self):return (self.current_page-1)*10@propertydef end(self):return self.current_page*10def page_str(self,all_item,base_url):all_page, div = divmod(all_item, 10)if div > 0:all_page += 1pager_str = ""# #默认可以看到的页码11个# # start = self.current_page - 5# end = self.current_page + 6# # #把页面动态起来传入起始和结束# for i in range(start, end):# # #判断是否为当前页# if i == self.current_page:# temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)# else:# temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)# # # 把标签拼接然后返回给前端# pager_str += tempif all_page <= 11:start = 1end = all_pageelse:if self.current_page <= 6:start = 1end = 11 + 1else:start = self.current_page - 5end = self.current_page + 6if self.current_page + 6 > all_page:start = all_page - 10end = all_page + 1#把页面动态起来传入起始和结束for i in range(start, end):#判断是否为当前页if i == self.current_page:temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)else:temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)# 把标签拼接然后返回给前端pager_str += tempreturn pager_strdef 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,'user_list.html',{'result':result,'pager_str':pager_str})
这样简单分页就完成了,现在我们可以在给他增加一个“上一页” & 下一页
我们可以把他给为一个列表,然后每次生成的标签append到列表中,然后分别在列表中最前面和后面增加,上一页和下一页
#/usr/bin/env python #-*- coding:utf-8 -*-from django.shortcuts import render from django.shortcuts import HttpResponse import models # Create your views here.class Pager(object):def __init__(self,current_page):self.current_page = int(current_page)#把方法伪造成属性(1) @propertydef start(self):return (self.current_page-1)*10@propertydef end(self):return self.current_page*10def page_str(self,all_item,base_url):all_page, div = divmod(all_item, 10)if div > 0:all_page += 1pager_list = []if all_page <= 11:start = 1end = all_pageelse:if self.current_page <= 6:start = 1end = 11 + 1else:start = self.current_page - 5end = self.current_page + 6if self.current_page + 6 > all_page:start = all_page - 10end = all_page + 1#把页面动态起来传入起始和结束for i in range(start, end):#判断是否为当前页if i == self.current_page:temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)else:temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)# 把标签拼接然后返回给前端 pager_list.append(temp)#上一页if self.current_page > 1:pre_page = '<a href="%s?page=%d">上一页</a>' % (base_url, self.current_page - 1)else:# javascript:void(0) 什么都不干pre_page = '<a href="javascript:void(0);">上一页</a>'#下一页if self.current_page >= all_page:next_page = '<a href="javascript:void(0);">下一页</a>'else:next_page = '<a href="%s?page=%d">下一页</a>' % (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):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,'user_list.html',{'result':result,'pager_str':pager_str})
最后写成模块,也可以吧分页的数量动态化!
前面说过关于XSS的问题,还有一种方式在后端告诉他是安全的即可,前端就不需要标记了。
导入并使用模块即可:
#!/usr/bin/env python #-*- coding:utf-8 -*-from django.utils.safestring import mark_safe#把拼接的HTML标记为安全的即可return mark_safe("".join(pager_list))
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Title</title></head><body><table>{% for line in result %}<tr><td>{{ line.username }}</td><td>{{ line.age }}</td></tr>{% endfor %}</table><div>{{ pager_str }}</div></body></html>
#!/usr/bin/env python #-*- coding:utf-8 -*-from django.utils.safestring import mark_safeclass Pager(object):def __init__(self,current_page):self.current_page = int(current_page)#把方法伪造成属性(1) @propertydef start(self):return (self.current_page-1)*10@propertydef end(self):return self.current_page*10def page_str(self,all_item,base_url):all_page, div = divmod(all_item, 10)if div > 0:all_page += 1pager_list = []if all_page <= 11:start = 1end = all_pageelse:if self.current_page <= 6:start = 1end = 11 + 1else:start = self.current_page - 5end = self.current_page + 6if self.current_page + 6 > all_page:start = all_page - 10end = all_page + 1#把页面动态起来传入起始和结束for i in range(start, end):#判断是否为当前页if i == self.current_page:temp = '<a style="color:red;font-size:26px;padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)else:temp = '<a style="padding: 5px" href="%s?page=%d">%d</a>' % (base_url,i,i)# 把标签拼接然后返回给前端 pager_list.append(temp)#上一页if self.current_page > 1:pre_page = '<a href="%s?page=%d">上一页</a>' % (base_url, self.current_page - 1)else:# javascript:void(0) 什么都不干pre_page = '<a href="javascript:void(0);">上一页</a>'#下一页if self.current_page >= all_page:next_page = '<a href="javascript:void(0);">下一页</a>'else:next_page = '<a href="%s?page=%d">下一页</a>' % (base_url, self.current_page + 1)pager_list.insert(0, pre_page)pager_list.append(next_page)return mark_safe("".join(pager_list))
转载于:https://www.cnblogs.com/bruceg/p/5553770.html
自定义分页(模块化)相关推荐
- python 换页_Python之路【第十九篇】自定义分页实现(模块化)
自定义分页 1.目的&环境准备 目的把分页写成一个模块的方式然后在需要分页的地方直接调用模块就行了. 环境准备Django中生成一个APP并且注册,配置URL&Views 配置URL ...
- GridView自定义分页导航
自己做的一个项目中所运用到的技术:| 1. 日历控件(带时分秒) 2. GridView 批量删除,自定义分页,定位页码 3. GridView 修改 ...
- Asp.net中DataGrid控件的自定义分页
使用实现起来虽然比较方便,但是效率不高,每次都需要读取所有页(整个记录集),而加载的只是其中一页,造成了资源的浪费,记录多又会使效率变得很低.下面通过DataGrid的自定义分页功能来减少资源使用和提 ...
- ASP.NET 2.0在SQL Server 2005上自定义分页
这篇文章讲述了如何利用SQL Server 2005的新特性来简单高效的实现分页.对于那些暂时还没用到SQL Server2005的人们,请看在大规模数据中的高效分页方法.如果需要,这篇文章会补上这里 ...
- GridView自定义分页样式(上一页,下一页,到第几页)(新手教程)
今天要为网站做一个文章列表,发现GridView的分页样式很难看,于是结合网上的例子,自己做了一个.不是很美观,不过还是很实用的,先看下效果吧,如图(1).演示地址http://www.veryam. ...
- DataList自定义分页
Asp.net里头,像DataList,Repeater,DataGrid,GridView,FormView包括Asp.net3.5中的ListView这几种服务器数据绑定控件,是在开发中经常需要用 ...
- Laravel自定义分页样式
Laravel 的分页组件默认为 Bootstrap 的分页样式,但如果我们用的并不是 Bootstrap 或者说分页的 HTML结构不一样,这时我们需要自定义分页.其实 Laravel 的分页组件是 ...
- Django框架详细介绍---cookie、session、自定义分页
1.cookie 在HTTP协议介绍中提到,该协议是无状态的,也就是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的 ...
- Sql Server 2005自定义分页
前面一篇随笔,我提到了Sql Server 2000的自定义分页,但是在sql server 2000中,要实现显示某一页,就返回那一页数据的效果的方法实在不尽人意.网上很多通用的分页存储过程,但看着 ...
最新文章
- Day 1 AR认知课 || AIRX三次方
- 剑指offer:面试题27. 二叉树的镜像
- Windows Server 2016 + Exchange 2016 +Office365混合部署(四)
- 快速上手用Python搭建自己的第一个pyecharts图表
- Windows Phone MultiBinding :Cimbalino Toolkit
- lintcode-514-栅栏染色
- 数据分析究竟在分析什么?
- 渝粤教育,我是客服,2022重返王者荣耀,再露凶残,欢迎约战
- android中资源文件的两种访问方式,在android开发中进行数据存储与访问的多种方式介绍...
- 隐藏方法不能实现多态性
- brew 、carthage 安装
- 我的 CDMA 往事
- 离散数学之数理逻辑01
- OpenV2X 社区第一次线上交流会成功举办
- 数控g71编程实例带图_数控车床编程G71 二型,编程实例
- P2114 起床困难综合症
- Eureka集群间通信
- Android系统 GPIO状态查询
- Reincarnation hdu4622 hash解法
- 揭秘三大运营商在5G专网的布局!