python2.0_day19_前端分页功能的实现

我们前面完成的客户纪录展示,只有4条,如果有上百条就不能在1页中全部展示了,那样是不人性化的.另外一次性取出来,数据量也比较大.假如现在有95条数据,我们想实现一个每页展示20条,那就分为5页.假如我们实现了,那么前端每一次请求就需要给后台提供参数了.这个参数就是告诉views里的视图函数我取第几页.需求分析:    95条,每页20条    第一次请求 返回20条,并且后端返回当前返回是第几页 ,所以第一次返回是1    点击下一页 1+1=2 ,把2传给后端,后端拿到后在把第二页的内容返回给前端,并且把当前返回的页这里是2,返回给前端.按照这个需求,我们自己写,也是很容易实现的(这是对于老手),但是这个分页功能属于一个常用而且通用的功能,Django就提供了Paginator模块来实现后台分页的功能.Django提供的是后台分页的功能,前端要使用bootstrap中的分页示例代码我们先看看Django中处理分页的模块都有哪些方法:
$python3.5 manage.py  shell
>>> from django.core.paginator import Paginator # 导入Paginator
>>> objects = [‘john‘,‘paul‘,‘george‘,‘ringo‘]
>>> p = Paginator(objects,2)    # 生成一个分页的实例,两个参数(objects是列表,2代表的是每2个元素分成一页.)
那我们来看看p这个实例有几个方法
>>> p.count             # 查看有多少个元素
4
>>> p.num_pages         # 查看总共有几页
2
>>> type(p.page_range)
<class ‘range‘>
>>> p.page_range        # 当我们想循环每一页时就需要用到这个. for num in p.page_range:page = p.page(1)
range(1, 3)
>>> page1 = p.page(1)   # p.page(num) 取第几页
>>> page1               # page1 显示这事第几页
<Page 1 of 2>
>>> page1.object_list   # 显示页里面的元素,以列表的方式
[‘john‘, ‘paul‘]
>>> p.object_list       # 显示p实例里有多少个元素
[‘john‘, ‘paul‘, ‘george‘, ‘ringo‘]

>>> page2 = p.page(2)   # 第二页
>>> page2.object_list   # 查看第二页有多少个元素
[‘george‘, ‘ringo‘]
>>> page2.has_next()    # 查看当前页是不是有下一页,如果有返回True,如果没有Flase
False
>>> page2.has_previous()    # 查看当前页是不是有上一页,如果有返回True,如果没有返回False
True
>>> page2.has_other_pages() # 查看除了当前页之外还有没有其它页,如果有返回True,如果没有返回False
True
>>> page1.next_page_number() # 查看当前页的下一页的页码
2
>>> page2.next_page_number()    # 查看当前页的下一页的页码,如果没有则报错
Traceback (most recent call last):
......
django.core.paginator.EmptyPage: That page contains no results
>>> page2.previous_page_number()    # 查看当前页的上一页的页码.
1
>>> page1.previous_page_number()    # 查看当前页的上一页的页码,如果没有则报错
Traceback (most recent call last):
......
django.core.paginator.EmptyPage: That page number is less than 1

>>> page1.start_index() # 查看当前页中,第一个元素在总列表的索引值
1
>>> page2.start_index() # 查看当前页中,第一个元素在总列表的索引值
3
>>> page1.end_index()   # 查看当前页中,最后一个元素在总列表的索引值
2
>>> page2.end_index()   # 查看当前页中,最后一个元素在总列表的索引值
4
>>> p.page(0)   # 当所取页超出p.page_range()范围,就会报错了
Traceback (most recent call last):
...
django.core.paginator.EmptyPage: That page number is less than 1
Django分页的官网https://docs.djangoproject.com/en/1.9/topics/pagination/

我们来看下后台中到底如何使用,我们从django中查看有详细的示例代码.按照这些示例代码完全没问题

我们在crm/views.py文件中的代码如下:
 1 from django.shortcuts import render
 2 from crm import models
 3 from django.core.paginator import  import Paginator,EmptyPage,PageNotAnInteger # 两个异常
 4 # Create your views here.
 5
 6 def dashboard(request):
 7     return render(request,‘crm/dashboard.html‘)
 8 def customers(request):
 9     customer_list = models.Customer.objects.all()
10     paginator = Paginator(customer_list,2) # 每页显示2条纪录
11     page = request.GET.get(‘page‘) #获取客户端请求传来的页码
12     try:
13         customer_list = paginator.page(page) # 返回用户请求的页码对象
14     except PageNotAnInteger:   # 如果请求中的page不是数字,也就是为空的情况下
15         customer_list = paginator.page(1)
16     except EmptyPage:
17         # 如果请求的页码数超出paginator.page_range(),则返回paginator页码对象的最后一页
18         customer_list = paginator.page(paginator.num_pages)
19
20     return render(request,‘crm/customers.html‘,{‘customer_list‘:customer_list})
需要注意的是:通过costomer_list = paginator.page(数字)获得的对象,是paginator分页实例,但是当我们对这个对象进行for循环时,遍历出来的还是里面的元素.所以我们可以在html模版中代码依然是直接对 custormer_list 进行for循环,我一开始还以为要用{% for custormer in customer_list.object_list %}呢,结果在官网的html示例代码中是{% for custormer in customer_list %}我试了下,两个都可以使用

然后我们在看下官网上给我们指引的需要在html模版文件中需要做的改动:

更改templates/crm/customer.html文件

 1 from django.shortcuts import render
 2 from crm import models
 3 from django.core.paginator import  import Paginator,EmptyPage,PageNotAnInteger # 两个异常
 4 # Create your views here.
 5
 6 def dashboard(request):
 7     return render(request,‘crm/dashboard.html‘)
 8 def customers(request):
 9     customer_list = models.Customer.objects.all()
10     paginator = Paginator(customer_list,2) # 每页显示2条纪录
11
12     page = request.GET.get(‘page‘) #获取客户端请求传来的页码
13
14     try:
15         customer_list = paginator.page(page) # 返回用户请求的页码对象
16     except PageNotAnInteger:   # 如果请求中的page不是数字,也就是为空的情况下
17         customer_list = paginator.page(1)
18     except EmptyPage:
19         # 如果请求的页码数超出paginator.page_range(),则返回paginator页码对象的最后一页
20         customer_list = paginator.page(paginator.num_pages)
21
22     return render(request,‘crm/customers.html‘,{‘customer_list‘:customer_list})

customer.html

访问http://127.0.0.1:8000/crm/customers,结果如图:

以上我们完成了一个最简单的分页.接下来我们可以对分页进行优化下.我们打开百度,随便搜索一个关键字

要实现这种只要在前端进行更改就行了,我们可以直接使用bootcss.com中找分页的组件.

我们将代码拷贝到我们的customer.html文件中,然后进行更改,最终代码如下:

 1 {% extends ‘base.html‘ %}
 2 {% block page-header %}
 3     Customers List
 4 {% endblock %}
 5 {% block page-content %}
 6     <table class="table table-hover">
 7         <thead>
 8             <tr>
 9                 <th>ID</th>
10                 <th>QQ</th>
11                 <th>姓名</th>
12                 <th>渠道</th>
13                 <th>咨询课程</th>
14                 <th>课程类型</th>
15                 <th>客户备注</th>
16                 <th>状态</th>
17                 <th>课程顾问</th>
18                 <th>日期</th>
19             </tr>
20         </thead>
21         <tbody>
22         {% for coustomer in customer_list.object_list %}
23             <tr>
24                 <td>{{ coustomer.id }}</td>
25                 <td>{{ coustomer.qq }}</td>
26                 <td>{{ coustomer.name }}</td>
27                 <td>{{ coustomer.source }}</td>
28                 <td>{{ coustomer.course }}</td>
29                 <td>{{ coustomer.get_course_type_display }}</td>
30                 <td>{{ coustomer.consult_memo|truncatechars:10 }}</td>
31                 <td class ="{{ coustomer.status }}"> {{ coustomer.get_status_display }} </td>
32                 <td>{{ coustomer.consultant }}</td>
33                 <td>{{ coustomer.date }}</td>
34             </tr>
35         {% endfor %}
36
37         </tbody>
38     </table>
39     <div class="pagination">
40
41         <nav>
42             <ul class="pagination">
43                 <li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
44                 <!--<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>-->
45                 <!--我们要想获得所有的页面是不是先要知道有多少页,然后对页码进行循环
46                 这里需要注意:我们知道paginator有一个方法page_range,可以获得range(1,总页数+1)这个<class ‘range‘>,但是我们这里的customer_list只是一个页码实例,它怎么获得range类型呢
47                 可以,可以使用customer_list.paginator.page_range这样就获得了range(1,总页数+1)这个<class ‘range‘>,接下来就是对这个range进行循环就可以了.
48                 -->
49
50                 {% for page_num in customer_list.paginator.page_range %}
51                     <li class="active"><a href="?page={{page_num}}">{{page_num}}<span class="sr-only">(current)</span></a></li>
52                 {% endfor %}
53             </ul>
54         </nav>
55     </div>
56 {% endblock%}

更改后的customer.html

我们浏览下http://127.0.0.1:8000/crm/customers/结果如下:

我们看到图中标签都是蓝色,这是不对的,是因为
<li class="active"><a href="?page={{page_num}}">{{page_num}}<span class="sr-only">(current)</span></a></li>
里的class = "active",所以我们应该写一个if,如果当前循环页的页码和当前页的页码一样时才active那么怎么获得当前页的页码呢.custormer_list.number就能获得代码如图:

再次访问http://127.0.0.1:8000/crm/customers/如图:

下面我们在代码中加入判断,让"上一页按钮"和"下一页按钮"生效代码如下:
 1     <div class="pagination">
 2
 3         <nav>
 4             <ul class="pagination">
 5                 {% if customer_list.has_previous %}
 6                     <li class=""><a href="?page={{customer_list.previous_page_number}}" aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>
 7                 {% endif %}
 8                 <!--<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>-->
 9                 <!--我们要想获得所有的页面是不是先要知道有多少页,然后对页码进行循环
10                 这里需要注意:我们知道paginator有一个方法page_range,可以获得range(1,总页数+1)这个<class ‘range‘>,但是我们这里的customer_list只是一个页码实例,它怎么获得range类型呢
11                 可以,可以使用customer_list.paginator.page_range这样就获得了range(1,总页数+1)这个<class ‘range‘>,接下来就是对这个range进行循环就可以了.
12                 -->
13                 {% for page_num in customer_list.paginator.page_range %}
14                     {% if page_num  == customer_list.number %}
15                         <li class="active"><a href="?page={{page_num}}">{{page_num}}<span class="sr-only">(current)</span></a></li>
16                     {% else %}
17                         <li class=""><a href="?page={{page_num}}">{{page_num}}<span class="sr-only">(current)</span></a></li>
18                     {% endif %}
19                 {% endfor %}
20
21                 {% if customer_list.has_next %}
22                     <li class=""><a href="?page={{customer_list.next_page_number}}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>
23                 {% endif %}
24
25             </ul>
26         </nav>
27     </div>
这时候页码功能就差不多了.

我们接着优化,这里我们只有2页内容,按照上面的代码,你有100页,它也会在页码中显示出来,这么一来就不人性化了.我们看到百度里,一般会显示指定数量的页码标签,并且选中的标签永远在最中间.如图

那么上图的效果如何实现呢?我们把视图重新改下,改成每一条纪录为一页,那么就会有4页,我们就设置成在前端显示3个页码标签.被选中的显示在中间.思路:    1.首先通过customer_list.num能知道当前页的页码.    2.循环显示页码的时候,判断比当前页码少多少可显示,多多少可显示,否则不显示    3.这里有一个聪明的做法,取循环的值-当前页页码所得差的绝对值就可.问题这是前端代码,没有abs(2-1)取绝对值的语法.那用什么语法?    前端的template前端里没有求绝对值的语法,怎么办呢?可以自己写,Django中允许自定义template的语法.接下来我们来看如何自定义前端语法.

自定义Django的template语法即自定义template tags(自定义模版标签)https://docs.djangoproject.com/es/1.9/howto/custom-template-tags/1.你要想写自定义标签,首先要在你的app目录,我们这里是crm目录下创建一个python包文件(目录名称必须是templatetags/),在这个目录下创建你的自定义标签.

2.自定义标签的内容怎么写呢?我们先看下官网上提供的一个示例代码,实现全大写的代码:
1     from django import template
2
3     register = template.Library() # 生成一个注册器
4
5     @register.filter # 注册到语法库,过滤语法 ,就是把数据输入进来,内部执行后把改变的结果在反回来
6     def alex_upper(value):
7         return value.upper()
前端模版想用这个自定义template 标签,前端页面得知道有这个,默认前端肯定不知道,所以你想在前端使用,首先要在前端导入一下:在{% extends ‘base.html‘%}下面一行导入,因为如果先导入会被覆盖.紧接着是如何在代码中使用.比如我们在显示name字段时,把英文字母全部大写.

完成上面代码,你以为成功了,我们访问测试http://127.0.0.1:8000/crm/customers/

结果出错了,为什么?因为要重启,这里是Django中为数不多更改后的内容需要重启的地方.$ python3.5 manage.py  runserver 127.0.0.1:8000重启后,我们看结果

至此简单的创建一个自定义的tempate 标签我们就已经会了,接下来我们就可以自定义取绝对值的自定义标签了.我们看到刚刚创建的自定义template tags中注册是:@register.filter用的是filter,filter过滤语法的特点是接收一个参数,处理后返回处理结果我们这里要取绝对值,就需要传入两个参数,一个是当前页的页码,还有一个for循环的页码.这就要用到支持多个参数的语法了叫做@register.simple_tagdjango 的@register.simple_tag可以写的很复杂,我们先不关,先用它实现我们简单的需求:
 1 from django import template
 2
 3 register = template.Library()
 4
 5 @register.filter
 6 def alex_upper(value):
 7     return value.upper()
 8
 9 @register.simple_tag
10 def guess_page(current_page,loop_num):
11     offset = abs(current_page - loop_num)
12     return offset
注意了,之前我们调用自定义的filter注册的方法是通过"|alex_upper"而现在我们是通过simple_tag注册的,调用的方法是:
    {% 函数名 参数1 参数2 %}
这里是:
    {% guess_page customer_list.number page_num %}
但是我们的问题来了,{% guess_page customer_list.num page_num %} 返回的是一个具体的数值,我们需要设置一个变量,接收函数调用后返回的值.但是前端是不能创建变量的,那么如何解决呢?我们看,guess_page返回的是字符串值,那么我们干脆就直接返回html代码,那么前端就可以就直接写这段代码就可以了{% guess_page customer_list.num page_num %}那么我们就把 guess_page函数重新改一遍:把前端代码的内容删掉:
    {% if page_num  == customer_list.number %}
        <li class="active"><a href="?page={{page_num}}">{{page_num}}<span class="sr-only">(current)</span></a></li>
    {% else %}
        <li class=""><a href="?page={{page_num}}">{{page_num}}<span class="sr-only">(current)</span></a></li>
    {% endif %}
然后把这段内容,放到guess_page函数里,但是要把内容用python实现.
@register.simple_tag
def guess_page(current_page,loop_num):
    offset = abs(current_page - loop_num)
    # 如果绝对值小于2,就返回page_ele
    if offset < 2:
        # 如果当前页码等于循环的页码,则class="active"
        if current_page == loop_num:
            page_ele = ‘‘‘
            <li class="active"><a href="?page={{%s}}">{{%s}}<span class="sr-only">(current)</span></a></li>
            ‘‘‘%(loop_num,loop_num)
        # 如果当前页码不等于循环的页码,则class=""
        else:
            page_ele = ‘‘‘
            <li class=""><a href="?page={{%s}}">{{%s}}<span class="sr-only">(current)</span></a></li>
            ‘‘‘%(loop_num,loop_num)
        return page_ele
我们访问http://127.0.0.1:8000/crm/customers/查看结果如图:

拿不能就返回字符串啊,当然Django中有处理的方法,用format_html()具体代码如下:
 1     from django import template
 2     from django.utils.html import format_html  # 引入format_html模块
 3
 4     register = template.Library()
 5
 6     @register.filter
 7     def alex_upper(value):
 8         return value.upper()
 9
10     # @register.simple_tag
11     # def guess_page(current_page,loop_num):
12     #     offset = abs(current_page - loop_num)
13     #     return offset
14     @register.simple_tag
15     def guess_page(current_page,loop_num):
16         offset = abs(int(current_page) - int(loop_num))
17         # 如果绝对值
18         if offset < 2:
19             if current_page == loop_num:
20                 page_ele = ‘‘‘
21                 <li class="active"><a href="?page=%s">%s<span class="sr-only">(current)</span></a></li>
22                 ‘‘‘%(loop_num,loop_num)
23             else:
24                 page_ele = ‘‘‘
25                 <li class=""><a href="?page=%s">%s<span class="sr-only">(current)</span></a></li>
26                 ‘‘‘%(loop_num,loop_num)
27             return format_html(page_ele)
访问http://127.0.0.1:8000/crm/customers/,查看结果

怎么处理这个None,简单在if offset < 2:不满足时返回空字符串代码如下
 1     @register.simple_tag
 2     def guess_page(current_page,loop_num):
 3         offset = abs(int(current_page) - int(loop_num))
 4         # 如果绝对值
 5         if offset < 2:
 6             if current_page == loop_num:
 7                 page_ele = ‘‘‘
 8                 <li class="active"><a href="?page=%s">%s<span class="sr-only">(current)</span></a></li>
 9                 ‘‘‘%(loop_num,loop_num)
10             else:
11                 page_ele = ‘‘‘
12                 <li class=""><a href="?page=%s">%s<span class="sr-only">(current)</span></a></li>
13                 ‘‘‘%(loop_num,loop_num)
14             return format_html(page_ele)
15         else:
16             return ‘‘
我们在访问http://127.0.0.1:8000/crm/customers/结果如图:

至此我们就实现了在Django框架结合bootstrap实现分页的功能.看似简单的一个功能,有那么知识!
时间: 2024-08-09 03:22:56

python2.0_day19_前端分页功能的实现的相关文章

python2.0_day19_充分使用Django_form实现前端操作后台数据库

在前面的<python2.0_day19_学员管理系统之前端用户交互系统>一节中,我们实现了前端展示customer客户纪录.在<python2.0_day19_前端分页功能的实现>一节中,我们实现了网页中最常用的分页功能.最终我们在访问客户咨询纪录表的前端页面的效果如图: 能实现这个效果,对于我们这种新手,算是小有成就了.那么接下来,我们想实现点击前面的ID号,1,2,3就能进入该条目的编辑页面.这也是在Django admin后台管理中常见到的.那么我们之前在<pytho

网站前端_JavaScript-项目经验.纯JavaScript实现客户端的分页功能?

项目简介: 说明: 此项目属于医院电子病例系统,由于历史原因,整个系统后台基于Java开发,前端使用Html+CSS+原生JavaScript,项目功能模块要求必须纯JS实现,而此次的任务是为住院病例页面编写一个客户端分页功能. 实现思路: 1. 基于客户端分页的前提是数据已经加载完毕,所以此功能模块必须等待数据加载完毕后再加载 2. 基于客户端分页的首页只需要显示24个患者信息即可 3. 上一页/当前页/下一页功能类似,基于当前页面传递同样的参数(页码, 限制患者数),所以自然而然想到了递归,

Django中使用JS通过DataTable实现表格前端分页,每页显示页数,搜索等功能

版本: django:2.1.7 python:3.7 Django架构中自带了后端分页的技术,通过Paginator进行分页,前端点击按钮提交后台进行页面切换. 优缺点:后端分页对于数据量大的场景有其优势,但页面切换比较慢. 后端分页python3代码如下: paginator = Paginator(stat_list, numtmp) try: flight_stats = paginator.page(1) except PageNotAnInteger: flight_stats =

jsp、js分页功能的简单总结

一.概述 首先,我们要明确为何需要分页技术,主要原因有以下: 1.分页可以提高客户体验度,适当地选择合适的数据条数,让页面显得更有条理,使得用户体验感良好,避免过多数据的冗余. 2.提高性能的需要.分页技术,有选择的加载某部分数据,在数据量较大的时候,分部分加载数据.显示数据,可以有效提高程序的性能,当然,单纯的js的分页技术并没有这种效果. 所以,分页技术是web技术中比较常用的技术,而下面讨论的主要是两种分页技术:一种是jsp的分页技术,其读取数据分批次读取,操作页数跳转的时候才加载相应页面

如何用angularjs制作一个完整的表格之二__表格分页功能

接上一次,这次主要介绍表格分页功能,由于项目需要这个案例是关于前端分页的方式,现在很少会这么用了,但如有需要可以参考其中的思路 html: 1.通过UL来展示页标,其中每个页标的li是通过异步加载从获取到不同的表格数据来动态生成的. <div class="pagination"> <ul style="float:right"> <li id="previous"><a href=""

jQuery插件实例六:jQuery 前端分页

先来看看效果: 对于前端分页,关键是思路,和分页算法.本想多说两句,可又觉得没什么可说的,看代码吧: 如何使用? $("#pging").zPagination({ 'navEvent':function(){ console.log('取数据Ajax'); } }); JS代码 //分页Pagination ; (function ($, window) { var defaults = { rowCount: 400, //总数据行数 navPage: 10, //每次显示多少页导

Vue.js 开发实践:实现精巧的无限加载与分页功能

https://segmentfault.com/a/1190000005351971#articleHeader9 本篇文章是一篇Vue.js的教程,目标在于用一种常见的业务场景--分页/无限加载,帮助读者更好的理解Vue.js中的一些设计思想.与许多Todo List类的入门教程相比,更全面的展示使用Vue.js完成一个需求的思考过程:与一些构建大型应用的高阶教程相比,又更专注于一些零碎细节的实现,方便读者快速掌握.致用. 需求分析 当一个页面中信息量过大时(例如一个新闻列表中有200条新闻

django分页功能,templatetags的应用

django 将不会将得到的html代码自动转化 from django.utils.html import format_html html =''' <a href='http://www.china.cn'>中国</a>''' format_html(html) django分页 分页功能基本操作 from django.core.import Paginator li=[11,12,13,22,24,25] p=Paginator(li,3) #将li传入,每页显示3条 p

Jquery分页功能

Jquery代码 /// <reference path="jquery-1.9.1-vsdoc.js" />//锚点var anchor="#apage";$(function(){    pagerFun();    $("#btnSearch").click(function(){        var name=$.trim($("#txtHospitalName").val());        var