django中的自定义分页器

1.什么是自定义分页器

当我们需要在前端页面展示的数据太多的时候,我们总不能将数据展示在一页上面吧!这时,我们就需要自定义一个分页器,将数据分成特定的页数进行展示,每一页展示固定条数的数据!

image

2.为什么要用自定义分页器

如上所说:为了将数据分成多页进行展示,分别阅读,方便查询!

image

3.如何使用自定义分页器

3.1 自定义分页器推导过程

虽然!我们有一个封装好的分页器源码,用的时候只需要cv大法就行,但是作为一名优秀的程序猿!!我们还是需要知道底层的逻辑是不是!!
image

我们需要明确的是,前端向后端请求的常用方式为get和post请求。分页的时候,我们应该采用get请求的方式给后端传输您需要转到的页数!!

其次我们还需要知道一个点,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 = ?
"""
下面需要研究current_page、per_page_num、start_page、end_page四个参数之间的数据关系
per_page_num = 10
current_page                start_page                  end_page
    1                           0                           10
    2                           10                          20
    3                           20                          30  
    4                           30                          40

per_page_num = 5
current_page                start_page                  end_page
    1                           0                           5
    2                           5                           10
    3                           10                          15  
    4                           15                          20
可以很明显的看出规律
start_page = (current_page - 1) * per_page_num
end_page =  current_page* per_page_num
"""

我们研究完当前页(current_page)、每页展示的数据条数(per_page_num)、每页数据的起始位置(start_page)和结束位置(end_page)之后,我们还需要知道的最重要的一点是:

一共需要从数据库取出的数据一共有多少条!!!

image

此时,我们就需要用到python中的一个内置方法divmod:它是功能是一个数除以另一个数时,返回余数和商!!如:

>>> divmod(100,10)
(10, 0)  # 10页
>>> divmod(101,10)
(10, 1)  # 11页
>>> divmod(99,10)
(9, 9)  # 10页
# 余数只要不是0就需要在第一个数字上加一

我们可以用它来判断我们一共需要多少页!

后端自定义分页器逻辑详解:

def book(request):
    if request.method == 'GET':
        current_page = request.GET.get('page',1) # 获取用户需要访问的页面,如果没有默认返回1
    try:   #异常捕获,因为前端返回的都是字符串,需要把他们都转成数字类型,方便下面做运算操作
        current_page = int(current_page)
    except Exception as e:
        current_page = 1  # 用户输入啥字母等也默认为1
    per_page_num = 10  #每页展示多少条数据
    start_page = (current_page - 1) * per_page_num  #当前页数起始数据
    end_page = current_page * per_page_num  #当前页结束数据
    book_num = models.Book.objects.all() #将所有数据查询出来
    all_count = book_num.count()  # 统计一共有多少数据
    num,more = divmod(all_count,per_page_num)  #divmod方法计算需要的总页数
    if more:
        all_page = num + 1 #more为余数,余为0,则刚刚好是num页数,不为0,则页数加1
    # 然后我们需要在html页面的分页器标签部分,for循环一下总共需要的num页数,但是有一个问题是,前端无法使用range()
    # 这就需要我们在后端进行循环,再传到前端
    html = ''
    a = current_page # 为了下面页码高亮调整
    if current_page <6:  #当页面小于6时,固定在6上面,为下面的for处理不出现页码负数
        current_page = 6
    # 访问第6页时,只会显示当前页-5和+6的底部页码数,但是当页面小于6时,页码会出现0甚至负数,所有我们需要对页面进行一个设置,就是上述的a
    for i in range(current_page-5,current_page+6):
        if a == i:
            # 当前页的页面高亮显示
            html += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)
        else:
            html += '<li><a href="?page=%s">%s</a></li>' % (i, i)
    book_queryset = book_num[start_page:end_page]
    return render(request,'book.html',locals())

前端页面部分:
<nav aria-label="Page navigation">
  <ul class="pagination">
    <li>
      <a href="#" aria-label="Previous">
        <span aria-hidden="true">&laquo;</span>
      </a>
    </li>
        {{ html|safe }}
    <li>
      <a href="#" aria-label="Next">
        <span aria-hidden="true">&raquo;</span>
      </a>
    </li>
  </ul>
</nav>

3.2 自定义分页器封装代码

封装好的分液器
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)

3.3 封装好分页器的使用

后端

# 先导入自己封装好的分液器模块,如何在使用
 def get_book(request):
   book_list = models.Book.objects.all()
   current_page = request.GET.get("page",1)
   all_count = book_list.count()
   page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10)
   page_queryset = book_list[page_obj.start:page_obj.end]
   return render(request,'booklist.html',locals())

前端

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            {% for book in page_queryset %}
            <p>{{ book.title }}</p>
            {% endfor %}
            {{ page_obj.page_html|safe }}
        </div>
    </div>
</div>

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:django中的自定义分页器 - Python技术站

(0)
上一篇 2023年4月2日
下一篇 2023年4月2日

相关文章

  • input与print语法

    1.input输入语法 input是用来接收用户输入的一种语法,实现计算机与用户之间的交互,改方法有一个返回值,返回的是用户输入的字符串! 语法:res = input(‘请输入您的账号:’) 在python3中,用户输入的数据类型将会被全部转成字符串类型。在python2中,用户输入什么数据类型,程序就会转成什么类型,指的注意的是,用户假如输入的数据类型错…

    Python开发 2023年4月2日
    00
  • 文章详情页制作

    url的设计 /usrname/article/1 /用户名/article/文章主键值 re_path(r’^(?P<username>\w+)/article/(?P<article_id>\d+)/$’,views.article_detail,name=’detail’), 视图函数的设计 # 七、文章详情页 def arti…

    Python开发 2023年4月2日
    00
  • 轮播图前端

    轮播图组件 <template> <div id=”banner”> <el-carousel height=”400px”> <!– 将banner_list循环–> <el-carousel-item v-for=”item in banner_list” :key=”item”> <…

    2023年4月2日
    00
  • JWT的介绍和使用

    JWT的含义 Json web token(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519),该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(sso)场景,JWT的声明一般被用来在身份提供者和服务者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其他业务逻辑所必须的声…

    2023年4月2日
    00
  • 模板语法之标签

    语法 {% 开始标签 %} …. {% 结束标签%} if标签 例:{% if … %} {% elif %} {% else %} {% endif %} if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。 for标签 # for 标签带有一个可选的{% empty %…

    Python开发 2023年4月2日
    00
  • 基础数据类型之集合

    1.集合的定义 在{}内用逗号分开多个元素,多个元素满足以下三个条件: 1.集合元素必须是不可变类型2.集合元素无序3.集合内元素没有重复(打印出来会自动去重) d = {} 默认是定义空字典 需要定义空集合,需要使用s = set() 2,集合的作用 (1)关系运算 # 如何取出这两个人共同的朋友呢? friend1=[‘zhang’,’yang’,’li…

    Python开发 2023年4月2日
    00
  • while循环语法

    while循环 循环的基本语法和使用 count = 0 # 定义一个初始条件 while 条件: 代码1 代码2 … count += 1 # 额,每循环一次+1,用来结束循环 退出循环的两种方式 方式一:将while后面的条件改成false,退出循环!该方式就是基本语法的使用方式!注意:改成false提交后面的代码还会执行,直到第二次判断开始结束循环…

    Python开发 2023年4月2日
    00
  • 进程

    1 什么是进程 进程是系统进行资源分配和调度的基本单位,进程表示程序正在执行的过程,是‘活的’,而程序就是一推躺在硬盘上的代码,是‘死的’。 2 进程的调度 1.先来先服务调度算法:对长作业有利,对短作业无利2.短作业优先调度算法:对短作业有利,对长作业无利3.时间片轮转法+多级反馈队列该方法是指,将时间片切成n份,每一份表示一个时间片,这些时间片有一个优先…

    2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部