• Django高级之分页器组件


    批量插入数据

    模板层models.py

    from django.db import models
    
    class Books(models.Model):
        name = models.CharField(max_length=32)
        price = models.DecimalField(max_digits=8,decimal_places=2)
        publish = models.CharField(max_length=32)

    建表别忘了执行数据库迁移命令哦

    python3 manage.py makemigrations
    
    python3 manage.py migrate

    路由层urls.py

    urlpatterns = [
        url(r'^books_page/', views.books_page), 
    ]

    视图层views.py

    # 往Book表里批量插入数据
    
    def books_page(request):
       # 第一种方案,每循环一次,操作一下数据库,性能低(相当于进行了1000次的数据库链接)
        # for i in range(1000):
        #     book=models.Books.objects.create(name='图书%s'%i,price=i+10,publish='东京出版社')
        #
       # 第二种方案,批量插入
        book_list=[]  # 实例化对象放到列表里
        for i in range(1000):
            book=models.Books(name='图书%s'%i,price=i+10,publish='东京出版社')
            book_list.append(book)
        # bulk_create一次性插入,batch_size分批往里面插
        models.Books.objects.bulk_create(book_list,batch_size=100)
    
        return HttpResponse('ok')
    
    # 当你想要批量插入数据的时候,使用ORM提供的 bulk_create 能够大大的减少操作时间

    Django的分页器(paginator)

    Django提供了一个新的类来帮助你管理分页数据,这个模块存放在django.core.paginator.py。 其中有两个核心类,一个是Paginator类,另一个是Page类。

    在页面显示分页数据,需要用到Django分页器组件

    from django.core.paginator import Paginator

    分页器的使用方法

    urlpatterns = [
        url(r'^books_page/', views.books_page), 
    ]
    路由层urls.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
        <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
    <div>
        <table class="table table-striped">
            <thead>
            <tr>
                <th>id</th>
                <th>书名</th>
                <th>价格</th>
                <th>出版社</th>
            </tr>
            </thead>
            <tbody>
            {% for book in book_list %}
                <tr>
                    <td>{{ book.id }}</td>
                    <td>{{ book.name }}</td>
                    <td>{{ book.price }}</td>
                    <td>{{ book.publish }}</td>
                </tr>
            {% endfor %}
    
            </tbody>
        </table>
    </div>
    
    <div>
    
        <nav aria-label="Page navigation">
            <ul class="pagination">
                <li>
                    <a href="#" aria-label="Previous">
                        <span aria-hidden="true">&laquo;</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">&raquo;</span>
                    </a>
                </li>
            </ul>
        </nav>
    </div>
    
    </body>
    </html>
    前端book_page.html

    视图层views.py及使用方法

    from django.shortcuts import render,HttpResponse,redirect
    from django.core.paginator import Paginator
    def books_page(request):
        book_list=models.Books.objects.all()  # 拿到所有的书籍
        paginator=Paginator(book_list,10)  # 实例化得到对象
        # Paginator对象的属性
        print(paginator.count) # 数据总条数
        print(paginator.num_pages) # 总页数
        print(paginator.per_page) # 每页显示条数
        print(paginator.page_range) # range(1, 101) 页码数可以从1拿到100
        print(paginator.page(2)) # page对象,拿出第2页
        # Page对象的属性和方法页
        page = paginator.page(2) # 当前所在页数
        print(page.has_next()) # 是否有下一页
        print(page.next_page_number()) # 下一页页码
        print(page.has_previous()) # 是否有上一页
        print(page.previous_page_number()) # 上一页页码
        print(page.object_list) # 分页之后的数据列表
        print(page.number)  # 当前页
    
        return render(request,'book_page.html',locals())

    分页器终极用法

    改吧改吧就能使哦

    urlpatterns = [
        url(r'^books_page/', views.books_page),
    ]
    urls.py
    # 分页器的终极使用
    def books_page(request):
        # 当前页码,用户访问首页默认是第一页,转成int类型
        current_num = int(request.GET.get('page_num', 1)) # 从前端获取page_num
        
        book_list = models.Books.objects.all()  # 拿到要展示的所有数据
    
        paginator = Paginator(book_list, 20) # 每页显示20条
        
        try:
            page = paginator.page(current_num) # 取到当前的页码数
        except Exception as e:
            current_num = 1  # 无论选择的大于或者小于强制等于1
            page = paginator.page(current_num)
            
        # 如果总页码数大于11
        if paginator.num_pages > 11:
            
            # 当前页码减5小于1,要生成1到12的列表(顾头不顾尾,共11个页码)
            if current_num - 5 < 1:
                page_range = range(1, 12)
                
            # 当前页码+5大于总页码,生成当前页码减10,到当前页码加1的列表(顾头不顾尾,共11个页码)
            elif current_num + 5 > paginator.num_pages:
                page_range = range(paginator.num_pages - 10, paginator.num_pages + 1)
                
            else: # 生成当前页码 - 5,到当前页码 + 6的列表
                page_range = range(current_num - 5, current_num + 6)
                
        # 其它情况,生成的列表就是pageinator的page_range
        else:
            page_range = paginator.page_range
    
        return render(request, 'book_page.html', locals())
    
    
    '''
    上一页 1 2 3 4 5 6 7 8 9 10 11 下一页
    
    上一页 21 22 23 24 25 26 27 28 29 30 31 下一页
    
    '''
    views.py
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>book_page.html</title>
        <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
        <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
        <script src="/static/jquery-3.3.1.js"></script>
    
    </head>
    <body>
    <div class="container-fluid">
        <div class="row">
    
            <div class="col-md-8 col-md-offset-2">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">图书列表展示</h3>
                    </div>
                    <div class="panel-body">
    
                        <table class="table table-striped">
                            <thead>
                            <tr>
                                <th>id</th>
                                <th>书名</th>
                                <th>价格</th>
                                <th>出版社</th>
                            </tr>
                            </thead>
                            <tbody>
                            {% for book in page.object_list %}
                                <tr>
                                    <td>{{ book.id }}</td>
                                    <td>{{ book.name }}</td>
                                    <td>{{ book.price }}</td>
                                    <td>{{ book.publish }}</td>
                                </tr>
                            {% endfor %}
    
                            </tbody>
                        </table>
                        <div class="text-center">
                            <nav aria-label="Page navigation">
                                <ul class="pagination">
                                    {% if page.has_previous %}
                                        <li>
                                            <a href="/books_page/?page_num={{ page.previous_page_number }}"
                                               aria-label="Previous">
                                                <span aria-hidden="true">&laquo;</span>
                                            </a>
                                        </li>
                                    {% else %}
                                        <li class="disabled">
                                            <a href="" aria-label="Previous">
                                                <span aria-hidden="true">&laquo;</span>
                                            </a>
                                        </li>
                                    {% endif %}
                                        {# 当前循环到的页码数,page_range是一个生成器对象 #}
                                    {% for foo in page_range %}
                                        {# 如果点中的那个数字等于当前页码数,则渲染成蓝色 #}
                                        {% if current_num == foo %}
                                            <li class="active"><a href="/books_page/?page_num={{ foo }}">{{ foo }}</a></li>
                                        {% else %}
                                            {# 不等于就正常渲染 #}
                                            <li><a href="/books_page/?page_num={{ foo }}">{{ foo }}</a></li>
                                        {% endif %}
                                    {% endfor %}
                                    {% if page.has_next %}
                                        <li>
                                            <a href="/books_page/?page_num={{ page.next_page_number }}" aria-label="Next">
                                                <span aria-hidden="true">&raquo;</span>
                                            </a>
                                        </li>
                                    {% else %}
                                        <li class="disabled">
                                            <a href="" aria-label="Next">
                                                <span aria-hidden="true">&raquo;</span>
                                            </a>
                                        </li>
                                    {% endif %}
                                </ul>
                            </nav>
                        </div>
    
                    </div>
                </div>
            </div>
        </div>
    
    </div>
    
    <div>
    
    </div>
    
    </body>
    </html>
    books_page.html

    自定义分页器的拷贝及使用(极力推荐)

    当我们需要使用到非django内置的第三方功能或者组件代码的时候,我们一般情况下会创建一个名为utils的文件夹,在该文件夹内对模块进行功能性划分。eg:mypage.py

    我们到了后期封装代码的时候,不再局限于函数,而是尽量朝面向对象去封装

    将下面封装好的模板拷贝到utils文件夹下的mypage.py(自定义的名字随意取)

    class Pagination(object):
        def __init__(self, current_page, all_count, per_page_num=2, pager_count=5):
            """
            封装分页相关数据
            :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)

    后端模板:视图层 views.py

    from utils.mypage import Pagination  # 导入模板
    # 书籍的展示
    def books(request):
        # 先查询出所有要展示的数据信息,
        book_queryset = models.Book.objects.all()
        current_page = request.GET.get('page',1) 
        all_count = book_queryset.count()
        # 传值生成对象
        page_obj = Pagination(current_page=current_page,all_count=all_count)
        # 直接对总数据进行切片操作
        page_queryset = book_queryset[page_obj.start:page_obj.end]
        # 将page_queryset传递到页面,替换之前的book_queryset
        return render(request,'books.html',locals())

    前端只需要这一行代码就可以实现分页

    <div class="text-center">{{ page_obj.page_html|safe }}</div>

    前端示例:book_list.html

    {% extends 'home.html' %}
    
    {% block main %}
        <script>
            $('.index').removeClass('active')
            $('.books').addClass('active')
            $('.publish').removeClass('active')
            $('.author').removeClass('active')
        </script>
        <div>
            <div class="panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">图书管理</h3>
                </div>
                <div class="panel-body">
                    <div>
                        <a href="/book_add/" class="btn btn-success pull-right">添加书籍</a>
                    </div>
                    <br>
                    <br>
    
                    <table class="table table-striped table-hover table-bordered">
                        <thead>
                        <tr>
                            <th>ID</th>
                            <th>书名</th>
                            <th>价格</th>
                            <th>出版日期</th>
                            <th>出版社</th>
                            <th>作者</th>
                            <th>操作</th>
                        </tr>
                        </thead>
                        <tbody>
                        {% for book in page_queryset %}
                            <tr>
                                <td>{{ book.id }}</td>
                                <td class="warning">{{ book.title }}</td>
                                <td class="info">{{ book.price }}</td>
                                <td class="dark">{{ book.publish_date|date:'Y-m-d' }}</td>
                                <td class="success">{{ book.publish.name }}</td>
                                <td>
                                    {% for author in book.authors.all %}
                                        {% if forloop.last %}
                                            {{ author.name }}
                                        {% else %}
                                            {{ author.name }}、
                                        {% endif %}
                                    {% endfor %}
                                </td>
                                <td>
                                    <a href="{% url 'book_edit' book.pk %}" class="btn btn-primary btn-xs">编辑</a>
                                    <a href="{% url 'book_delete' book.pk %}" class="btn btn-danger btn-xs">删除</a>
                                    <button type="button" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#myModal" id="bbb" onclick="AA('{{ html }}')">
      Launch
    </button>
                                </td>
                            </tr>
                        {% endfor %}
                        </tbody>
                    </table>
                    {# 只需要这一行代码就可以实现分页 #}
                  <div class="text-center">{{ page_obj.page_html|safe }}</div>
                </div>
            </div>
        </div>
    
    {% endblock %}

    从来就没有正确的选择,我们只不过是要努力奋斗,使当初的选择变得正确。
  • 相关阅读:
    Codeforces 992C(数学)
    Codeforces 990C (思维)
    Codeforces 989C (构造)
    POJ 1511 Invitation Cards(链式前向星,dij,反向建边)
    Codeforces 1335E2 Three Blocks Palindrome (hard version)(暴力)
    POJ 3273 Monthly Expense(二分)
    POJ 2566 Bound Found(尺取前缀和)
    POJ 1321 棋盘问题(dfs)
    HDU 1506 Largest Rectangle in a Histogram(单调栈)
    POJ 2823 Sliding Window(单调队列)
  • 原文地址:https://www.cnblogs.com/gfeng/p/14589017.html
Copyright © 2020-2023  润新知