首页 > 其他分享 >Django高级之-分页器

Django高级之-分页器

时间:2023-05-06 21:36:00浏览次数:38  
标签:count 分页 self 高级 Django current html pager page

目录

分页推导

分页的几个参数:

  1. 当前第几页
  2. 总数据量有多少(从数据库中查询出来)
  3. 每页展示20条(自己规定的)
  4. 总数据量 / 每页展示的条数 = 总页数

首先我们需要明确的时候,get请求也是可以携带参数的,所以我们在朝后端发送查看数据的同时可以携带一个参数告诉后端我们想看第几页的数据。

queryset对象的切片参数

其次我们还需要知道一个点,queryset对象是支持索引取值和切片操作的,但是不支持负数索引情况

接下来我们就可以推导我们的自定义分页器步骤了

current_page = request.GET.get("page",1)  # 获取用户想访问的页码 ,如果没有,默认展示第一页

try:  # 由于后端接受到的前端数据是字符串类型所以我们这里做类型转换处理加异常捕获
  current_page = int(current_page)
except Exception as e:
  current_page = 1

# 还需要定义页面到底展示几条数据
per_page_num = 10  # 一页展示10条数据
 
# 需要对总数据进行切片操作 需要确定切片起始位置和终止位置
start_page = ? 
end_page = ?
"""
下面需要研究start、end分别与current_page、per_page_num参数之间的数据关系
per_page_num = 10
current_page            start                   end
1                          0                    10
2                          10                   20
3                          20                   30
4                           30                  40


per_page_num = 5
current_page            start                   end
1                          0                    5
2                          5                    10
3                          10                   15
4                          15                   20

可以很明显的看出规律
start = (current_page - 1) * per_page_num
end = current_page * per_page_num
"""

数据总页数获取

问题1:总数据有100条,每页展示10条,总共需要几页?
答案:10条
问题2:总数据有101条,每页展示10条,总共需要几页?
答案:11条
问题3:如何通过代码算出到底需要多少条?

"""
	总数据量     每页展示的数据     总页数
	100   			10  		 10
	101				10			 11
	99				10		     10
	divmod(100, 10)
"""

我们可以判断元祖的第二个数字是否为0从而确定到底需要多少页来展示数据

book_queryset = models.Book.objects.all()
all_count = book_queryset.count()  # 数据总条数
page_count, rem = divmod(all_count, per_page_num)
if rem :  # 有余数则总页数加一
  page_count += 1

循环看需要展示几个li

    page_html = ''
    # for i in range(1, page_count+1):
    for i in range(current_page - 5, current_page + 6):  # 只展示11个页码数
        if i == xxx:  # 如果展示页数等于当前页数,因为current_page在小于6时,被限制了,所以要新建一个变量来代替当前页
            # 页码高亮
            # href="?page=%s":前面为空,就是朝当前地址提交,问号后面是参数
            page_html += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            page_html += '<li ><a href="?page=%s">%s</a></li>' % (i, i)

至此分页器大致的功能及思路我们就已经大致清楚了

最后我们只需要利用start和end对总数据进行切片取值再传入前端页面就能够实现分页展示

    book_list = book_queryset[start:end]
    return render(request, 'index.html', locals())

接下来就剩下渲染前端页面了。

推导分页的原理代码

数据准备

models.py中建立表:

from django.db import models


# Create your models here.
class Book(models.Model):
    title = models.CharField(max_length=64)
    
# test.py中批量插入数据
from django.test import TestCase

# Create your tests here.
import os

if __name__ == '__main__':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day58.settings")
    import django
    django.setup()

    from app01 import models
    book_list = []
    for i in range(1000):
        book_list.append(models.Book(title='第%s本书' % i))

    models.Book.objects.bulk_create(book_list)

views.py后端页面:

def index(request):
    # book_list支持切片
    # book_list = models.Book.objects.all()[0:10] # 第一页的数据
    # book_list = models.Book.objects.all()[10:20] # 第二页的数据

    # queryset对象
    book_queryset = models.Book.objects.all()
    # 总数量
    all_count = book_queryset.count()
    # 每页展示多少条数据
    per_page_num = 10
    # 我让你查看第10页的数据
    # 我们要知道当前是第几页,接收问号后的参数
    # get('page', 1)是当第一个参数没有值时,默认输出给定的第二个参数的数字
    current_page = request.GET.get('page', 1)  # 当接收不到当前页码的时候,就默认是第一页
    current_page = int(current_page)  # 前端的数据时字符串类型的

    # 每一页的起始序号和结束序号
    start = (current_page - 1) * per_page_num
    end = current_page * per_page_num

    # 计算出总共多少页
    page_count, rem = divmod(all_count, per_page_num)
    if rem:  # 余数有值,页数需要加一
        page_count += 1

    xxx = current_page
    if current_page < 6:
        current_page = 6

    # 循环看,需要展示几个li
    page_html = ''
    # for i in range(1, page_count+1):
    for i in range(current_page - 5, current_page + 6):  # 只展示11个页码数
        if i == xxx:  # 如果展示页数等于当前页数,因为current_page在小于6时,被限制了,所以要新建一个变量来代替当前页
            # 页码高亮
            # href="?page=%s":前面为空,就是朝当前地址提交,问号后面是参数
            page_html += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            page_html += '<li ><a href="?page=%s">%s</a></li>' % (i, i)

    book_list = book_queryset[start:end]
    return render(request, 'index.html', locals())

前端index.html页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>推导分页的原理</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{# 循环1000条数据 #}
{% for book in book_list %}
    <p>
        {{ book.title }}
    </p>
{% endfor %}

<nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        {# 模板中无法使用range函数,不能传参,循环页数需要在后端执行 #}
        {# 展示循环后的所有li #}
        {{ page_html|safe }}

        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>
</body>
</html>

终极大法

上面是自定义分页器开发流程的基本思路,我们不需要掌握代码的编写,只需要明白原理即可。

以后再实际项目中,会经常用到非django 的第三方工具,对于这种第三方工具,我们一般会在django中新建一个文件夹叫 utils,以后很多封装的代码都使用用面向对象的写法

自定义分页器封装代码

class Pagination(object):
    def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param pager_count:  最多显示的页码个数
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page < 1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager

        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property  # 把方法伪装成属性
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):  # 循环的前端的标签
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []
        # 添加前面的nav和ul标签
        page_html_list.append('''
                    <nav aria-label='Page navigation>'
                    <ul class='pagination'>
                ''')
        first_page = '<li><a href="?page=%s">首页</a></li>' % (1)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,)
            else:
                temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,)
        page_html_list.append(last_page)
        # 尾部添加标签
        page_html_list.append('''
                                           </nav>
                                           </ul>
                                       ''')
        return ''.join(page_html_list)  # 用空字符串拼接
    

自定义分页器使用

本次使用,可以在Django项目中新建一个utils文件夹,新建一个py文件(mypage.py),复制上述代码放到该py文件中即可。

后端

views.py文件:

def index(request):
    from utils.mypage import Pagination  # 导入类

    # 2.获取参数数据
    # current_page, all_count, per_page_num=2, pager_count=11
    # 2.1 current_page:当前页,从前端用户点击的数据传到问号后面
    current_page = request.GET.get('page', 1)
    # 2.2 all_count:总页数,计算数据表中的个数
    book_queryset = models.Book.objects.all()
    all_count = book_queryset.count()
    # 2.3 per_page_num可以在配置文件中设置
    '''
        # 每页展示多少条数据
        PER_PAGE_NUM = 10
    '''
    # 从配置文件中读取数据
    from django.conf import settings
    per_page_num = settings.PER_PAGE_NUM

    # 1.实例化对象
    page_obj = Pagination(current_page, all_count, per_page_num=per_page_num)

    # 3.展示所有数据,切片[对象点属性:对象点属性]
    book_list = book_queryset[page_obj.start:page_obj.end]

    # 4.获取li标签,对象点方法
    page_html = page_obj.page_html()
    return render(request, 'index.html', locals())

从配置文件中读取数据

"""
方式1:
    from django.conf import settings 
方式2:
    from 项目名 import settings
        
    方式2只能获取settings里面的数据,配置文件中没有,就直接报错.
    方式1中的settings是Django底层源码中的配置,使用这个,先去你自己文件中的配置文件中查找数据,如果找不到,去Django底层中的settings中再查找,再找不到才会报错。
"""

前端

index.html前端文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>推导分页的原理</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{# 循环1000条数据 #}
{% for book in book_list %}
    <p>
        {{ book.title }}
    </p>
{% endfor %}

<nav aria-label="Page navigation">
    <ul class="pagination">
        <li>
            <a href="#" aria-label="Previous">
                <span aria-hidden="true">&laquo;</span>
            </a>
        </li>
        {# 模板中无法使用range函数,不能传参,循环页数需要在后端执行 #}
        {# 展示循环后的所有li #}
        {{ page_html|safe }}

        <li>
            <a href="#" aria-label="Next">
                <span aria-hidden="true">&raquo;</span>
            </a>
        </li>
    </ul>
</nav>

</body>
</html>

标签:count,分页,self,高级,Django,current,html,pager,page
From: https://www.cnblogs.com/zjyao/p/17378488.html

相关文章

  • Django框架——cookie与session简介、django操作cookie与session、django中间件
    cookie与session简介"""回忆:HTTP协议四大特性 1.基于请求响应 2.基于TCP、IP作用于应用层之上的协议 3.无状态 不保存客户端的状态 4.无连接"""最开始的网站都不需要用户注册所有人来访问获取到的数据都是一样的随着互联网的发展很多网站需要指定当前用户的状态cook......
  • Django与Ajax
    目录一什么是Ajax二Ajax语法三案例1.通过Ajax,实现前端输入两个数字,服务器做加法,返回到前端页面2.前端反序列化的不同方式方式1:前端js反序列化方式2:ajax设置dataType参数方式3:Django的序列化模块四前后端传输数据的编码格式(理论)1.application/x-www-form-urlencoded2.multipa......
  • 前端自定义分页
    <el-tablesize="mini"stripeborderfitheight="406px"highlight-current-row:header-cell-style="{background:'#F0F3F8'}":data="historyResearch......
  • 算法之高级算法
    关键字:算法之高级算法高级算法包括:动态规划,贪心算法(1)动态规划动态规划算法是通过整合子问题来解决整个问题的,也就是说通过子问题的求解,可以得出次问题的解。动态规划关键是找出问题求解方程,即找到子问题和问题解的关系。例如:跳台阶问题题目:一......
  • django中间件
    目录一、django中间件什么是中间件?如何自定义中间件二、django中间件三个了解的方法三、django中间件五个方法的执行流程详解四、基于django中间件的功能设计功能设计介绍如何利用字符串导入模块功能模拟一、django中间件什么是中间件?官方的说法:中间件是一个用来处理Django的......
  • django内置序列化组件(drf前身)
    目录一、django内置序列化组件(drf前身)一、django内置序列化组件(drf前身)一、django内置序列化组件(drf前身)这里的内置序列化组件,其实就是实现将后端数据,存放到字典中或是存放到列表中有序输出。这里是我们用JsonResponse模块自己实现的代码'''前后端分离的项目视图函数......
  • django分页器
    目录一、分页器思路二、自定义分页器的使用一、分页器思路分页器主要听处理逻辑代码最后很简单推导流程 1.queryset支持切片操作(正数) 2.研究各个参数之间的数学关系 每页固定展示多少条数据、起始位置、终止位置 3.自定义页码参数 current_page=request.GET......
  • django视图层与cbv源码分析
    目录一、视图层之必会三板斧二、JsonResponse对象两种序列化数据的方式方式一:使用json模块方式二:使用JsonResponse对象使用JsonResponse对象序列化除字典外的数据类型如果给JsonResponse对象内部的json代码传参三、视图层之request对象获取文件四、视图层之FBV与CBV概念介绍五、CB......
  • django模板层
    目录一、模板层1.模板语法传值2.模板语法传值特性3.模板语法之过滤器(内置函数)lengthsliceaddfilesizeformatdatetruncatecharstruncatewordssafe二、模板层之标签分支结构iffor循环with(定义变量名)三、自定义过滤器、标签及inclusion_tag(了解)四、母版(模板)的继承与导入(重要)......
  • django生命周期流程图与django路由层
    目录一、django请求生命周期流程图二、django路由层1.路由匹配2.转换器3.正则匹配不同版本的区别正则匹配斜杠导致的区别4、正则匹配的无名有名分组分组匹配无名分组有名分组三、反向解析1.引入反向解析2.反向解析使用3.有名无名反向解析(动态路由反向解析)四、路由分发五、名称空间......