zoukankan      html  css  js  c++  java
  • Django分页的实现

    Django分页的实现

    分页介绍

    分页是网页浏览中常见到的一种形式,在数据量较大时,一个页面显示不全,采取分割数据由用户选择进行显示的方式。

    基本实现

    技术点

    1. 通过切片得到数据库中数据的一部分来显示。即为分页当前页面显示的数据。
    2. 通过 GET 方法从 URL 当中获取当前页的页码,由页码进行切片分割。
    3. 页面中的页码由服务端直接返回字符串来显示。

    前端代码

    注: 其中的样式类使用的 bootstrap 的。

    <div class="container">
        <table class="table table-bordered">
            <thead>
            <tr>
                <th>序号</th>
                <th>id</th>
                <th>书名</th>
            </tr>
            </thead>
            <tbody>
            {% for book in books %}
                <tr>
                    <td>{{ forloop.counter }}</td>
                    <td>{{ book.id }}</td>
                    <td>{{ book.title }}</td>
                </tr>
            {% endfor %}
    
            </tbody>
        </table>
    
        <nav aria-label="Page navigation">
            <ul class="pagination">
    
                {{ page_html|safe }}
    
    
            </ul>
        </nav>
    </div>
    

    Django views 的代码

    def books(request):
        all_books = models.Book.objects.all()
        page_num = request.GET.get("pages")
        page_num = int(page_num)
        data_start = (page_num - 1) * 10
        data_end = page_num * 10
    
        total_count = models.Book.objects.all().count()
        per_page = 10
        total_page, m = divmod(total_count, per_page)
    
        if m > 0:
            total_page += 1
    
        print(total_count)
    
        page_books = all_books[data_start: data_end]
    
        page_html_list = []
    
        for i in range(1, total_page+1):
            temp = '<li><a href="/books/?pages={0}">{0}</a></li>'.format(i)
            page_html_list.append(temp)
    
        # 转成字符串
        page_html = "".join(page_html_list)
        print(page_html)
    
        return render(request, "books.html", {"books": page_books, "page_html": page_html})
    
    

    结果与分析

     

    基本结果

     

    可以看出,页面将全部的页码全都显示出来,不美观也没必要。

    进一步改善需求:

    1. 当前页面仅显示一定数量的页码,页码的数量是固定的。
    2. 在页码数量固定的前提下,当前页码处于中间,前后有相同的页码数。且当前页码要为 active 状态。
    3. 增加首页、尾页页码,点击可跳转到首页及尾页。
    4. 增加前一页、后一页功能。点击可跳到前一页或者后一页。且当前页处于首页时前一页不可点击,同样,当前页处于尾页时后一页不可点击。

    我的改善步骤

    1. 先实现一半一半

    # 设置最大页码数
    max_page = 11
    half_max_page = max_page // 2
    
    # 开始页和尾页自然为当前页加上最大页码数的一半
    page_start = page_num - half_max_page
    page_end = page_num + half_max_page
    
    # 同时,生成 li 标签的循环也要进行更改
        for i in range(page_start, page_end + 1):
            temp = '<li><a href="/books/?pages={0}">{0}</a></li>'.format(i)
            page_html_list.append(temp)
    

    2. 特殊情况一:页码前面出现负值

    因为是由当前值减去半大值得到的首页页码数,所以当当前页码小于一定值时会出现负值,此时将首页页码设置为 1 ,尾页页码设置为最大页码数。

    if page_start < 1:
        page_start = 1
        page_end = max_page
    

    3. 特殊情况二:页码后面出现空白页

    同样,尾页页码大于一定值时,会显示出更多的页码但那些页码是超过数据范围的,当前页会显示空白页。

    解决办法:首页页码设置为 总页数 - 最大页码数 + 1 ,尾页页码设置为总页数。

    if page_end >= total_page:
        page_start = total_page - max_page + 1
        page_end = total_page
    

    4. 加上首页

    首页就是将 li 标签中的链接里的 href 固定为第一页的链接形式。

    page_html_list.append('<li><a href="/books/?pages=1">首页</a></li>')
    

    5. 加上尾页

    尾页就是将 li 标签中的链接里的 href 固定为第最后一页的链接形式。

    page_html_list.append('<li><a href="/books/?pages={0}">尾页</a></li>'.format(total_page))
    

    6. 前一页

    依旧是改链接,将链接中的 pages 值减一。

    page_html_list.append('<li><a href="/books/?pages={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num - 1))
    

    7. 加上后一页

    依旧是改链接,将链接中的 pages 值加一。

    page_html_list.append('<li><a href="/books/?pages={}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(page_num + 1))
    

    8. 解决最后一页时点后一页

    常理来说当前页处于最后一页时,后一页应该不允许点击。否则会出现页码不断增大,而页面无数据的情况。

    if page_num == total_page:
        page_html_list.append(
            '<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>')
    else:
        page_html_list.append(
            '<li><a href="/books/?pages={}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(
                page_num + 1))
    

    9. 解决在首页处点前一页

    常理来说当前页处于首页时,前一页应该不允许点击。否则会出现页码不断减小,出现负数,而页面无数据的情况。

    if page_num == 1:
        page_html_list.append(
            '<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>')
    else:
        page_html_list.append(
            '<li><a href="/books/?pages={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num - 1))
    

    10. 如果数据量少,页数也少

    当数据量较少,甚至不够最大页码数的时候,根据情况将最大页码数设置为总页数。

    max_page = 11
    
    if total_page < max_page:
        max_page = total_page 
        
    half_max_page = max_page // 2
    page_start = page_num - half_max_page
    page_end = page_num + half_max_page
    

    11. 对当前页加上活动 active 样式类

    这个很简单,如果当前页面的 pages 值等于页码数时,直接在 li 标签中加入 active 样式类即可,我这里使用的是 bootstrap 。

    for i in range(page_start, page_end + 1):
     if i == page_num:
            temp = '<li class="active"><a href="/books/?pages={0}">{0}</a></li>'.format(i) 
        else:
            temp = '<li><a href="/books/?pages={0}">{0}</a></li>'.format(i)
        page_html_list.append(temp)
    

    12. 实现对输入页码数非数字及超过总页码数的判断

    处理下 URL 中 pages 值为非数字和大数字的问题。

    • 非数字:默认跳转到首页
    • 大数字(超过总页码数):默认跳到最后一页
    try:
        page_num = int(page_num)
        # 如果输入页码数过大,默认跳到最后一页
        if page_num > total_page:
            page_num = total_page
    except Exception as e:
        page_num = 1
    

    结果展示

     

    改善后的分页
    改善后的分页

     

    完整代码

    def books(request):
        all_books = models.Book.objects.all()
    
        page_num = request.GET.get("pages")
    
        total_count = models.Book.objects.all().count()
        per_page = 10
        total_page, m = divmod(total_count, per_page)
    
        if m > 0:
            total_page += 1
    
        # 12. 实现对输入页码数非数字及超过总页码数的判断
        try:
            page_num = int(page_num)
            # 如果输入页码数过大,默认跳到最后一页
            if page_num > total_page:
                page_num = total_page
        except Exception as e:
            page_num = 1
    
        data_start = (page_num - 1) * 10
        data_end = page_num * 10
    
        page_books = all_books[data_start: data_end]
    
        # 1. 先实现一半一半
        max_page = 11
        # 10. 如果数据量少,页数也少
        if total_page < max_page:
            max_page = total_page
        half_max_page = max_page // 2
        page_start = page_num - half_max_page
        page_end = page_num + half_max_page
    
        # 2. 特殊情况一:页码前面出现负值
        if page_start < 1:
            page_start = 1
            page_end = max_page
    
        # 3. 特殊情况二:页码后面出现空白页
        if page_end >= total_page:
            page_start = total_page - max_page + 1
            page_end = total_page
    
        page_html_list = []
    
        # 6. 前一页
        # page_html_list.append('<li><a href="/books/?pages={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num - 1))
    
        # 9. 解决在首页处点前一页
        if page_num == 1:
            page_html_list.append(
                '<li class="disabled"><a href="#"><span aria-hidden="true">&laquo;</span></a></li>')
        else:
            page_html_list.append(
                '<li><a href="/books/?pages={}"><span aria-hidden="true">&laquo;</span></a></li>'.format(page_num - 1))
    
        # 4. 加上首页
        page_html_list.append('<li><a href="/books/?pages=1">首页</a></li>')
    
        for i in range(page_start, page_end + 1):
            # 11. 对当前页加上活动active样式类
            if i == page_num:
                temp = '<li class="active"><a href="/books/?pages={0}">{0}</a></li>'.format(i)
            else:
                temp = '<li><a href="/books/?pages={0}">{0}</a></li>'.format(i)
            page_html_list.append(temp)
    
        # 5. 加上尾页
        page_html_list.append('<li><a href="/books/?pages={0}">尾页</a></li>'.format(total_page))
    
        # 7. 加上后一页
        # page_html_list.append('<li><a href="/books/?pages={}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(page_num + 1))
    
        # 8. 解决最后一页时点后一页
        if page_num == total_page:
            page_html_list.append(
                '<li class="disabled"><a href="#" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>')
        else:
            page_html_list.append(
                '<li><a href="/books/?pages={}" aria-label="Next"><span aria-hidden="true">&raquo;</span></a></li>'.format(
                    page_num + 1))
    
        # 转成字符串
        page_html = "".join(page_html_list)
    
        return render(request, "books.html", {"books": page_books, "page_html": page_html})
    
    

    总结

    能够成功实现分页,但,这在 views 当中的一个函数中实现的,可以看出代码量很大,现实中不可能只有一个数据表需要分页,每次都写这么多代码显然利用率很低。

    下一步将分页封装成一个类,只需要根据需要实例化该类就能实现分类,利用率极大提升。

    GitHub地址:https://github.com/protea-ban/oldboy/tree/master/s9day71/ormday71

  • 相关阅读:
    EF 学习代码
    VS10 调试 新功能
    高级编程 实验代码
    事务 代码
    ADO.NET的新功能:MARS(Multiple Active Result Set) 及 异步执行命令
    Log4Net
    获得CheckBoxList最后一个被操作的项
    在存储过程中用事务
    ASP.NET服务端添加客户端事件
    GridView遍历各行的控件和控件事件
  • 原文地址:https://www.cnblogs.com/banshaohuan/p/9485710.html
Copyright © 2011-2022 走看看