zoukankan      html  css  js  c++  java
  • django中的分页器组件

    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.如果都不符合,那么就显示在中间

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

    第一种情况:

    第二种情况:

    第三种情况:

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

  • 相关阅读:
    host 文件位置
    Django 前后端分离开发配置 跨域
    pycharm 关闭单词拼写检查(Typo: In word 'cacheable' )
    Python : argument name should be lowercase 警告处理解决方法
    pycharm 变量名 (Shadows built-in name 'id' )问题
    三体
    12.URL下载网络资源
    11.UDP多线程在线咨询
    10.UDP实现聊天
    9.UDP
  • 原文地址:https://www.cnblogs.com/xiaoyafei/p/9837002.html
Copyright © 2011-2022 走看看