zoukankan      html  css  js  c++  java
  • Django15-分页功能

    一、背景

    当用户请求数据时,如果查询出数据结果较多,这时不应该将所有数据一次性返回给用户展示在同一个页面上,可以使用分页功能将数据分批次返回给用户,即可以减轻服务器每次查询所有数据的压力,也可以提升前端展示效果。

    分页功能可以自己实现,也可以使用Django内置的分页器。

    一、自己实现

    将分页功能单独封装成类,再在views中调用

    新建utils目录中的paginate.py用于封装分页类

    from django.utils.safestring import mark_safe
    
    class Paginate:
        
        def __init__(self, obj_all, page_id, obj_max=10, page_max=10):
            
            self.obj_total = obj_all.count()
    	  # 分页 每页显示的条目数,默认最多显示10条记录
    	  self.obj_max = obj_max
            # 每页最多显示的页码个数
            self.page_max = page_max
            
            try:
                # 如果获取不到page参数,将page_id默认设置成1
                self.page_id = page_id
            except Exception as e:
                self.page_id = 1
            
            # 总页码数为page_num
            self.page_total, more = divmod(self.obj_total, obj_max)
            if more:
                # 如果有余数,则页码数加1
                self.page_total += 1
        
        # 第1页切片,[0:10],取id为0-9的10条记录
        # 第2页切片,[10:20],取id为10-19的10条记录
        # 第n页切片,[(n-1)*10:n*10]
           #通过@property将方法封装成属性,在调用实例化对象.方法时就不需要加括号执行
        @property
        def obj_start(self):
            obj_start = (self.page_id - 1) * self.obj_max
            return obj_start
        
        @property
        def obj_end(self):
            obj_end = self.page_id * self.obj_max
            return obj_end
        
        @property
        def obj_id_start(self):
            # 第1页序号从1-10,第2页序号从11-20,而前端forloop.counter是从0开始,所以每页序号起始值要加上(n-1)*10
            obj_id_start = (self.page_id - 1) * self.page_max
            return obj_id_start
        
        @property
        def page_start(self):
            # 每页的页码范围
            page_start = (self.page_id - 1) // self.obj_max * self.page_max + 1
            return page_start
        
        @property
        def page_end(self):
            page_end = self.page_start + self.page_max
            # 如果结束页码大于总页码,就以总页码数为结尾
            if page_end > self.page_total:
                page_end = self.page_total + 1
            return page_end
        
        @property
        def page_previous(self):
            # 向前翻页,如果页面起始值为1,则向前翻页链接禁用
            if self.page_start == 1:
                page_previous = '<li class="disabled"><a aria-label="Previous"><span aria-hidden="true">«</span></a></li>'
            
            else:
                page_previous = '<li><a href="?page=%s" aria-label="Previous"><span aria-hidden="true">«</span></a></li>' 
                                % (self.page_start - self.obj_max)
            return mark_safe(page_previous)
        
        @property
        def page_next(self):
            # 向后翻页,最后一页向后翻页链接禁用
            if self.page_end == self.page_total + 1:
                page_next = '<li class="disabled"><a aria-label="Next"><span aria-hidden="true">»</span></a></li>'
            else:
                page_next = '<li><a href="?page=%s" aria-label="Next"><span aria-hidden="true">»</span></a></li>' 
                            % (self.page_start + self.obj_max)
            return mark_safe(page_next)
    

    views.py文件中只需要实例化分页类并传参即可

    def user_list(request):
        user_all = models.User.objects.all()
        #获取当前页面Url中的?page=id值,默认为1
        page_id = int(request.GET.get('page', 1))
        #实例化分页类
        paginate = Paginate(user_all, page_id)
    
        #返回参数,使用对象.参数的方法调用,由于类中使用了@property装饰器将方法封装成属性,所以不需要加括号即可执行
        return render(request, 'user/user_list.html',
                      {'user_all': user_all[paginate.obj_start:paginate.obj_end],
                       'page_total': range(paginate.page_start, paginate.page_end),  # 显示页码范围
                       'obj_id_start': paginate.obj_id_start,
                       'page_id': paginate.page_id,
                       'page_previous': paginate.page_previous,
                       'page_next': paginate.page_next,
                       })
    

    user_list.html前端渲染

    {#分页#}
    <div>
        <nav aria-label="Page navigation">
            <ul class="pagination">
    
            {#向前翻页链接#}
                {{ page_previous }}
    
                {% for num in page_total %}
                    {#num等于当前页码时,显示active#}
                    <li {% if page_id == num %}class="active"{% endif %}><a href="?page={{ num }}">{{ num }}</a></li>
                {% endfor %}
    
            {#向后翻页链接#}
                {{ page_next }}
            </ul>
        </nav>
    </div>
    

      

    二、Django内置Paginator类

    导包
    from django.core.paginator import Paginator

    1、通过Paginate构造一个分页器实例,两个参数分别是将要分类的对象列表和每页显示的数量

    paginate = Paginate(obj_list, per_page_number)
    例如
    user_all = models.User.objects.all()
    paginate = Paginator(user_all, 10)

    paginate 对象属性

    • count,对象总数
    • num_pages,页码总数
    • page_range,可以获取所有页码范围,从1开始page_range = paginate.page_range

    常见错误:

    • InvalidPage,page()传递无效页码
    • PageNotAnInteger,page()传递的不是整数
    • Empty,page()传递的值有效,但是没有数据

    2、分页对象(具体某一页)获取,通过Paginator的page()方法获取

    例如想要获取第1页的数据
    user_obj = paginate.page(1)

    user_obj对象属性:

    • objects_list 当前页面中所有的数据对象
    • number 当前页的页码值
    • paginate 当前page关联的Paginator对象,如果一个页面中有多个分页器时使用

    user_obj对象方法:

    • has_previous() 判断是否有上一页
    • has_next() 判断是否有下一页
    • has_other_pages()判断是否有上一页或下一页
    • privious_page_number 返回上一页的页码
    • next_page_number() 返回下一页的页码
    • len() 返回当前页的数据个数

    例子:

    views.py

    from django.views.generic import TemplateView
    from django.core.paginator import Paginator
    from user import models
    
    
    class UserList(TemplateView):
        template_name = 'user_list.html'
    
        def get_context_data(self, **kwargs):
            page = int(self.request.GET.get('page'))
            context = super().get_context_data(**kwargs)
            user_all = models.User.objects.all()
            # 定义分页器对象,筛选页面为page的对象
            paginate = Paginator(user_all, 10)
            context['users_page'] = paginate.page(page)
    
            # 定义开始页码和结束页面,每次只显示10个
            div, mod = divmod(page, 10)
            page_start = div * 10 + 1 if mod else div
            page_end = page_start + 10 if (page_start + 10) < paginate.num_pages else paginate.num_pages + 1
            context['page_range'] = range(page_start, page_end)
    
            # 判断是否可以向前翻10页和向后翻10页
            if page_start > 10:
                context['page_start_privious'] = page_start
            if page_start + 10 < paginate.num_pages:
                context['page_start_next'] = page_start
    
            return context

    user_list.html

    {% extends 'base.html' %}
    {% block body %}
        <table class="table">
            <tr>
                <td>id</td>
                <td>username</td>
            </tr>
            {% for user in users_page.object_list %}
                <tr>
                    <td>{{ user.id }}</td>
                    <td>{{ user.username }}</td>
                </tr>
            {% endfor %}
        </table>
        <nav aria-label="Page navigation">
            <ul class="pagination">
                {#向前翻10页#}
                {% if page_start_privious %}
                    <li>
                        <a href="{% url 'user_list' %}?page={{ page_start_privious|add:-10 }}" aria-label="Previous">
                            <span aria-hidden="true">&laquo;</span></a>
                    </li>
                {% endif %}
    
                {#向前翻页#}
                {% if users_page.has_previous %}
                    <li>
                        <a href="{% url 'user_list' %}?page={{ users_page.previous_page_number }}" 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 %}
    
                {# 页码 #}
                {% for page in page_range %}
                    {#如果page与当前页码相等时,显示亮色#}
                    <li {% ifequal page users_page.number %}class="active" {% endifequal %}><a
                            href="{% url 'user_list' %}?page={{ page }}">{{ page }}</a></li>
                {% endfor %}
    
    
                {#向后翻页#}
                {% if users_page.has_next %}
                    <li>
                        <a href="{% url 'user_list' %}?page={{ users_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 %}
    
            {# 向后翻10页 #}
            {% if page_start_next %}
                <li>
                    <a href="{% url 'user_list' %}?page={{ page_start_next|add:10 }}" aria-label="Next">
                        <span aria-hidden="true">&raquo;</span>
                    </a>
                </li>
            {% endif %}
            </ul>
        </nav>
    
    {% endblock %}
  • 相关阅读:
    poj3411
    2241 排序二叉树
    1004 四子连棋
    Poj1482
    poj2046
    Poj3087
    poj3414
    php使用flock堵塞写入文件和非堵塞写入文件
    HTML样式以及使用
    高效程序猿的狂暴之路
  • 原文地址:https://www.cnblogs.com/dxnui119/p/10999198.html
Copyright © 2011-2022 走看看