django的组件-分页器

引入分页器

在博客园中,如果每个人都发表一篇文章的话,如果咱们不进行分页的话,那么博客园的首页将会变得异常庞大,而且你永远不知道你要拉到什么什么时候才能拉到最底部,此时咱们的分页器就派上了用场,规定每个html页面只显示多少篇文章,给我们带来了大大的便利。

以下是博客园的分页器:

此时咱们需要做的就是这样一个类似的分页器。

分页器demo

创建数据库模型

我们首先做的就是数据库的模型,在这里给Book表定义了两个字段,title和price:

from django.db import models

# Create your models here.

class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)

然后我们需要运行数据库迁移命令:

python3 manage.py makemigrations

python3 manage.py migrate

因为没有对数据库进行特殊设置,则默认使用的是sqlite数据库,此时咱们点击pycharm查看新创建的数据库:

此时表创建出来了,那么数据从哪来呢?我们肯定是不可能手写的,所以,我们使用批量增加的方式将100条数据添加到数据库中。

url控制器

需要给程序提供一个入口,当用户输入127.0.0.1:8000/index便进行驶入匹配,如果成功则进入到视图函数中:

from django.contrib import admin
from django.urls import path
from app01 import views urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]

views视图函数

from django.shortcuts import render
from .models import Book
# Create your views here. def index(request):
# 通过批量插入bulk_create的方式插入数据,这种方式是一条sql插入100条数据
book_list = []
for i in range(100):
book = Book(title='boos_%s' % i, price=i*i)
book_list.append(book) Book.objects.bulk_create(book_list) book_list = Book.objects.all() return render(request, 'index.html', locals())

此时咱们就成功创建了视图函数,那么如果我们想将所有的数据展示出来的话,咱们需要一个index.html。

templates模板

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for book in book_list %}
<li>{{ book.title }}&nbsp;&nbsp;&nbsp;{{ book.price }}</li>
{% endfor %} </ul> </body>
</html>

此时咱们将项目启动起来,然后去浏览器查看:

此时的100条数据全部生成了,要记住的是:当数据批量插入后,需要将批量插入数据库的语句给注释掉。

为什么要用分页器

我们可以查看到100条数据就已经这么多了,但是数据不是一成不变的吗,所以我们需要使用分页器。

导入分页器

在视图函数中导入分页器需要用到这么一句话:

from django.core.paginator import Paginator

此时我们导入的是Paginator类,我们需要实例化成对象,那么这个对象就有自己的属性和方法:

实例化Pagintor对象

需要在视图函数中添加这么一句话来实例化对象:

# 进行实例化
paginator = Paginator(book_list, 10)

这句话的意思就是对book_list进行分页,每页显示10条数据。

那么我们说过,实例化的对象有自己的属性和方法,这里有三个属性,分别是:count、num_pages、page_range

# 实例化的方法和属性
print('总数:', paginator.count)
print('总页数:', paginator.num_pages)
print('页码的列表:', paginator.page_range)

此时让我们重新发送一个请求,然后再pycharm中查看打印结果:

此时就已经获取到了总数、总页数了,此时我们就可以进行下一步操作了。

获取每一页的数据

这个我们可想而知,肯定是1页10条数据,那么我们此时就需要得到这个页码:

# 获取当前页码
current_page_num = int(request.GET.get('page', 1))

request.GET.get('page')获取当前的页码,1代表的是默认显示第一页。

那么我们只是拿到了这个页码,这个数据从哪里拿呢?肯定是从分页器对象里面拿了:

# 根据页码拿到数据

current_page = paginator.page(current_page_num)

此时,这个current_page就是某一页的数据,然后我们需要在模板中更新语法成:

<ul>
{% for book in current_page %}
<li>{{ book.title }}&nbsp;&nbsp;&nbsp;{{ book.price }}</li>
{% endfor %}
</ul>

此时大功告成,我们刷新浏览器就能看到结果了。

如果我们想访问第二页的数据,那么我们需要在浏览器输入http://127.0.0.1:8001/index/?page=2就能访问第二页的数据:

此时咱们就大功告成了,展示下源代码:

# views.py

from django.shortcuts import render
from .models import Book
from django.core.paginator import Paginator
# Create your views here. def index(request):
'''
# 通过批量插入bulk_create的方式插入数据,这种方式是一条sql插入100条数据
book_list = []
for i in range(100):
book = Book(title='boos_%s' % i, price=i*i)
book_list.append(book) Book.objects.bulk_create(book_list)
''' book_list = Book.objects.all() # 进行实例化
paginator = Paginator(book_list, 10) # 实例化的方法和属性
print('总数:', paginator.count)
print('总页数:', paginator.num_pages)
print('页码的列表:', paginator.page_range)
# print(request.GET.get('page')) current_page_num = int(request.GET.get('page', 1))
current_page = paginator.page(current_page_num) return render(request, 'index.html', locals())
# urls.py

from django.contrib import admin
from django.urls import path
from app01 import views urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.index),
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<ul>
{% for book in current_page %}
<li>{{ book.title }}&nbsp;&nbsp;&nbsp;{{ book.price }}</li>
{% endfor %}
</ul>
</body>
</html>

没跟上的同学检查下代码。

分页器优化1

你们真的以为大功告成了吗?当然是没有的,举个简单的来说,如果page=-1的话,或者超过了最大页数的话,会怎么样?

报错了,既然报错了咱们就需要捕获异常,因为我们输入的是-1或者10以上都会报错,那么不如让都跳转到第一页去:

# 异常捕获
try:
current_page_num = int(request.GET.get('page', 1))
current_page = paginator.page(current_page_num)
except Exception as e:
current_page = paginator.page(1)

那么当我们再次输入-1的时候,就没有问题了:

那么这个问题就解决了。

分页器优化2

咱们需要在浏览器自己输入这个page是不是特别麻烦,所以,我们需要利用bootstrap来实现点击跳转,具体的就是引入bootstrap的分页器。

我们需要在index.html中添加bootstrap分页器组件:

# 添加bootstrap分页器组件

<nav aria-label="Page navigation">
<ul class="pagination">
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
<li><a href="#">1</a></li>
<li><a href="#">2</a></li>
<li><a href="#">3</a></li>
<li><a href="#">4</a></li>
<li><a href="#">5</a></li>
<li>
<a href="#" aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
</ul>
</nav>

那么这个时候咱们再去浏览器刷新的时候,就可以看到效果,当然,这些标签点击了也是没有任何作用的:

接下来咱们需要对每个li设置动作;

有多少页就设置多少个li

因为咱们直接引用的bootstrap组件就只有5个,所以我们有多少页就需要设置多少给li标签:

# 

{% for item in paginator.page_range %}
<li><a href="?page={{ item }}">{{ item }}</a></li>
{% endfor %}

首先这个paginator是一个分页器对象,然后呢page_range表示的页码的列表,那么我们对这个进行循环的话,就可以做到有多少页就设置多少个li标签了。

这里是浏览器刷新后的效果:

然后当我们点击这1-10就可以实现跳转了:

现在呢是完成了这个标签的,但是我们发现没有,你点击了5然后跳转到了第5页,你从请求url中看到了这是第5页,但是这个li标签却看不出来,所以我们还需要将点击的Li标签加一个class:

为点击的li标签添加class样式

咱们在views视图中获取到了每一页的页码current_page_num,然后我们在模板中也拿到了页码item,那么我们如果让这两个值相同的话,就给它加一个样式:

{% for item in paginator.page_range %}
{% if current_page_num == item %}
<li class="active"><a href="?page={{ item }}">{{ item }}</a></li>
{% else %}
<li><a href="?page={{ item }}">{{ item }}</a></li>
{% endif %} {% endfor %}

下面是浏览器上看到的效果

上一页和下一页

因为咱们的上一页和下一页是没有进行设置的,所以点击是没有进行任何跳转的。

首先解决咱们的下一页,思路是这样的:比如我们现在在第9页上,对第九页进行判断,如果存在下一页那就跳转到下一页去,如果没有,那么这个li标签就不能跳转,即给他禁止:

# 下一页

{% if current_page.has_next %}
<li>
<a href="?page={{ current_page.next_page_number }}" aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
{% else %}
<li class='disabled'>
<a href="#" aria-label="Next">
<span aria-hidden="true">下一页</span>
</a>
</li>
{% endif %}

看一下效果图:

那么同理,上一页也是这样做到的:

# 上一页
{% if current_page.has_previous %}
<li>
<a href="#" aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
{% else %}
<li class="disabled">
<a href="#" aria-label="Previous">
<span aria-hidden="true">上一页</span>
</a>
</li>
{% endif %}

当到了第一页的时候,就不能点击上一页了。

扩展知识点

首先让我们看一下现象

如果领导吩咐每一页只显示5行数据的话,那么就会有20页,那么如果一页就显示2条数据的话呢?所以这些肯定是不合理的,咱们需要根据这个页码进行修改:

current_page_num = int(request.GET.get('page', 1))  # 显示第一页的页码
if paginator.num_pages > 11: # 如果总页数大于19,就进入到这个判断中
if current_page_num-5 < 1: # 如果当前所在的页数减去5页小于1
page_range = range(1, 11) # 那么页码的范围就是1-11 elif current_page_num+5 > paginator.num_pages: # 如果当前页数+5大于总页数
page_range = range(paginator.num_pages-11, paginator.num_pages+1) # 那么此时页码的范围就是总页数减去11到总页码+1
else:
page_range = page_range = range(current_page_num-5, current_page_num+5) # 其余情况就显示在中间
else:
page_range = paginator.page_range

当咱们的请求发过去,只有两种情况:

1.总页数大于11

2.总页数小于11

如果小于11的话,那么就走下面的else,如果页数大于11,那么就走上面的条件判断,此时的条件判断分为三种情况(因为我们想让这个页码一直显示在中间):

1.如果当前页码减去5页的话小于1页,那么此时页码的范围就是1-11

2.如果当前页码加上5页大于总页数的话,那么此时的页码范围就是当前页数减去11页到当前页数加上1页之间,左合右开

3.如果都不符合,那么就显示在中间

那么此时刷新浏览器就能看到:

第一种情况:

第二种情况:

第三种情况:

那么此时咱们就完成了分页器。

django中的分页器组件的更多相关文章

  1. Django中的form组件

    Django中的form组件有两大作用 1.验证获取正确的结果或者错误信息 2.生成html代码 一.为什么需要form组件呢? 在写form表单,提交数据时,自己写验证的代码是一件非常困难的事情. ...

  2. django中的forms组件

    form介绍 用户需要向后端提交一些数据时,我们常常把这些数据放在一个form表单里,采用form标签,里面包含一些input等标签把用户的数据提交给后端. 在给后端提交数据的时候,我们常常也需要对于 ...

  3. django中的ajax组件

    目录 django中的ajax 向服务器发送请求的途径 Ajax的特点 基于jquery实现的ajax请求 利用ajax实现计算器 利用ajax实现登陆认证 利用form表单进行文件上传 利用ajax ...

  4. (31)django中的分页器

    book_list = models.Book.objects.all()    #查出指定表中的所有数据paginator = Paginator(book_list,2)    #实例化对象,传入 ...

  5. django中使用Form组件

    内容: 1.Form组件介绍 2.Form组件常用字段 3.Form组件校验功能 4.Form组件内置正则校验 参考:https://www.cnblogs.com/liwenzhou/p/87478 ...

  6. django中的forms组件(权限信息校验,增删改查)

    1.用处 1.用户请求数据验证 2.自动生成错误信息 3.打包用户提交的正确信息 4.如果其中有一个错误了,其他的正确,则保留上次输入的内容 5.自动创建input标签并可以设置样式 6.基于form ...

  7. Pyhon之Django中的Form组件

    Pyhon之Django中的Form组件   新手上路 Django的Form主要具有一下几大功能: 生成HTML标签 验证用户数据(显示错误信息) HTML Form提交保留上次提交数据 初始化页面 ...

  8. Django中的admin组件分析

    admin的使用介绍 django-admin的使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.可以在项目的 setting ...

  9. Flask-wtforms类似django中的form组件

    一.安装 pip3 install wtforms 二.简单使用 1.创建flask对象 from flask import Flask, render_template, request, redi ...

随机推荐

  1. ng-model 数据不更新 及 ng-repeat【ngRepeat:dupes】错误

    一.ng-include 引入的文件中 ,ng-model 数据不更新 例如, $scope.username = “Jones”  .此时,在 ng-include 引入的文件中,直接使用 ng-m ...

  2. python json 文件读写

    import json test_dict = {,,,} print(test_dict) print(type(test_dict))#字典 #dumps 将数据转换成字符串 json_str = ...

  3. tmp for cassandra batch delete

    now i have no time to verify this bash script. it is hard for me to delete each data via primary key ...

  4. servlet生命周期深入理解

    什么是Servlet Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中 ...

  5. Codeforces B - Tavas and SaDDas

    535B - Tavas and SaDDas 方法一:打表大法. 代码1: #include<bits/stdc++.h> using namespace std; ]={,,,,,,, ...

  6. TimeZone 时区 (JS .NET JSON MYSQL) + work week 闰年

    来源参考 : http://www.cnblogs.com/qiuyi21/archive/2008/03/04/1089456.html 来源参考 : http://walkingice.blogs ...

  7. PHP消息队列之Beanstalk

    Beanstalk,一个高性能.轻量级的分布式内存队列

  8. java web mysql.jar java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

    java.lang.ClassNotFoundException: com.mysql.jdbc.Driver 折腾了一上午,找到了这错误的原因.哎……悲剧! 确认包已经被导入web工程目录. 原来是 ...

  9. LeetCode--122--卖卖股票的最佳时机II

    问题描述: 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 设计一个算法来计算你所能获取的最大利润.你可以尽可能地完成更多的交易(多次买卖一支股票). 注意:你不能同时参与多笔交易( ...

  10. CF1082G Petya and Graph

    题意 定义图权 = 图中边权总和 - 图中点权总和(空图的图权=0),求 n 个点 m 条边的无向图最大权子图. 把边看成点,这个点与两个原图中的点连边.直接最小割求最大闭合子图即可.