分页

  • 一、分页基本原理:

from django.shortcuts import render

# Create your views here.


USER_LIST = []

for i in range(1, 666):
    dic = {'root':'root'+str(i), 'age':i}
    USER_LIST.append(dic)

def index(request):
    # 获取当前页码
    current_page = request.GET.get('p')
    current_page = int(current_page)

    # 设置上一页和下一页的页码
    if current_page <= 1:
        prev_page = 1
    else:
        prev_page = current_page - 1
    next_page = current_page + 1

    # 设置每页展示条目数
    per_page_count = 10

    # 计算展示数据的切片区间
    start_item = (current_page - 1) * per_page_count
    end_item = current_page * per_page_count

    USER = USER_LIST[start_item: end_item]

    return render(request, 'index.html',{'USER': USER, 'prev_page': prev_page, 'next_page': next_page})

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

{% for item in USER %}
    <p>{{ item.root }}-{{ item.age }}</p>
{% endfor %}

<span><a href="?p={{ prev_page }}">上一页</a></span>
<span><a href="?p={{ next_page }}">下一页</a></span>

</body>
</html>

展示样例:

  • 二、Django 内置分页:

注意:

- 包括 Paginator、 Page 两个对象
- 页面调用的时候使用:include

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger    # 导入django分页模块
# Create your views here.

# 模拟数据
USER_LIST = []

for i in range(1, 666):
    dic = {'root':'root'+str(i), 'age':i}
    USER_LIST.append(dic)


def index1(request):
    # 获取当前页码
    current_page = request.GET.get('p')
    
    # 创建 Paginator 对象,里面包括如下属性和对象:
    paginator = Paginator(USER_LIST, 10)    # 需传入全部数据USER_LIST,如果是数据库数据则传入models.xx.objects.all()即可,后面的参数是每页展示条数

    # 全部数据:USER_LIST,=》得出共有多少条数据
    # per_page: 每页显示条目数量
    # count: 数据总个数
    # num_pages: 总页数,也可表示最后一页
    # page_range: 总页数的索引范围,如: (1,10),(1,200)
    # page: page对象(封装着是否具有下一页;是否有上一页)

    try:
        # 创建 Page 对象,里面包括如下属性和对象:
        posts = paginator.page(current_page)    # 需传入当前页current_page

        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表,已经切片好的数据
        # number                当前页
        # paginator             paginator对象

    except PageNotAnInteger:    # 如果传入的页码不是整数,返回第一页
        posts = paginator.page(1)
    except EmptyPage:    # 如果传入的页码是空值,返回最后一页
        posts = paginator.page(paginator.num_pages)

    return render(request, 'index1.html', {'posts': posts})

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <ul>
        {% for item in posts.object_list %}
            <p>{{ item.root }}-{{ item.age }}</p>
        {% endfor %}
    </ul>

    {% if posts.has_previous %}
        <a href="?p={{ posts.previous_page_number }}">上一页</a>
        {% else %}
        <a href="#">上一页</a>
    {% endif %}
    {% if posts.has_next %}
        <a href="?p={{ posts.next_page_number }}">下一页</a>
    {% endif %}

    <span>
        {{ posts.number }}/{{ posts.paginator.num_pages }}
    </span>

</body>
</html>

可以将 "翻页" 和 "页码展示" 的通用部分写入一个pager.html的文件中,所有页面直接使用 {% include %} 标签导入分页部分即可:

1、在templates文件夹下创建分页文件夹:例如下面的 include 文件夹

2、在 include 文件夹里创建分页部分的 html 文件:例如下面的 pager.html 文件

3、把分页和页码展示的通用部分放到 pager.html 文件中:pager.html 的内容如下

{% if posts.has_previous %}
    <a href="?p={{ posts.previous_page_number }}">上一页</a>
    {% else %}
    <a href="#">上一页</a>
{% endif %}
{% if posts.has_next %}
    <a href="?p={{ posts.next_page_number }}">下一页</a>
{% endif %}

<span>
    {{ posts.number }}/{{ posts.paginator.num_pages }}
</span>

4、前端页面用 {% include %} 标签导入 pager.html 文件即可:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <ul>
        {% for item in posts.object_list %}
            <p>{{ item.root }}-{{ item.age }}</p>
        {% endfor %}
    </ul>

    {% include 'include/pager.html' %}

</body>
</html>

展示样例:

  • 三、扩展Django内置分页—加入页码显示:

创建自定义的扩展分页类 CustomPaginator,继承 Paginator 类:

多传入两个自定义参数:

1、当前页码:current_page

2、显示的页码总数:per_pager_num,最好取奇数

一共需传入:

  - 当前页

  - 最多显示页码数:7

  - 所有数据

  - 每页显示条数:30

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger  # 导入django分页模块

# Create your views here.

# 模拟数据
USER_LIST = []

for i in range(1, 666):
    dic = {'root': 'root' + str(i), 'age': i}
    USER_LIST.append(dic)

# 扩展内置分页,创建自定义的扩展分页类 CustomPaginator,继承 Paginator 类
class CustomPaginator(Paginator):
    def __init__(self, current_page, per_pager_num, *args, **kwargs):
        # 当前页
        self.current_page = int(current_page)
        # 页面下方最多显示的页码数量 11
        self.per_pager_num = int(per_pager_num)

        super(CustomPaginator, self).__init__(*args, **kwargs)

    # 当前页
    # self.current_page
    # 最多显示的页码数量 11
    # self.per_pager_num
    # 总页数
    # self.num_pages

    # 计算显示的页码数范围
    def pager_num_range(self):
        # 总页数小于最多显示的页码数,range范围取1到总页数+1(开区间所以得+1)
        if self.num_pages < self.per_pager_num:    # 总页数3页,显示的页码数11页
            return range(1, self.num_pages+1)    # 显示范围是 1-3页

        # 总页数特别多
        part = int(self.per_pager_num/2)    # 算出最多显示页码数的一半,例如显示11页,此处就是5
        
        # 处理选择页码数在1-5页的情况
        if self.current_page <= part:    # 当前页码数 <= 显示页数的一半
            return range(1, self.per_pager_num+1)    # 显示范围是 1-11页
        
        # 处理选择页码数在最后5页的情况
        if (self.current_page+part) > self.num_pages:    # 当前页+显示页码数的一半 > 总页数
            return range(self.num_pages-self.per_pager_num+1, self.num_pages+1)    # 显示范围是 (总页数-显示页数+1) 到 最后一页

        # 处理大多数中间页码的情况,例如当前页是第10页,显示范围是 5-15页
        return range(self.current_page-part, self.current_page+part+1)    # 显示范围是  当前页-显示页码数的一半  到  当前页+显示页码数的一半


def index2(request):
    # 获取当前页码
    current_page = request.GET.get('p')

    # 创建 Paginator 对象,里面包括如下属性和对象:
    paginator = CustomPaginator(current_page, 11, USER_LIST, 10)  # 需传入全部数据USER_LIST,如果是数据库数据则传入models.xx.all()即可,后面的参数是每页展示条数

    # 全部数据:USER_LIST,=》得出共有多少条数据
    # per_page: 每页显示条目数量
    # count: 数据总个数
    # num_pages: 总页数,也可表示最后一页
    # page_range: 总页数的索引范围,如: (1,10),(1,200)
    # page: page对象(封装着是否具有下一页;是否有上一页)

    try:
        # 创建 Page 对象,里面包括如下属性和对象:
        posts = paginator.page(current_page)  # 需传入当前页current_page

        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表,已经切片好的数据
        # number                当前页
        # paginator             paginator对象

    except PageNotAnInteger:  # 如果传入的页码不是整数,返回第一页
        posts = paginator.page(1)
    except EmptyPage:  # 如果传入的页码是空值,返回最后一页
        posts = paginator.page(paginator.num_pages)

    return render(request, 'index2.html', {'posts': posts})

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <ul>
        {% for item in posts.object_list %}
            <p>{{ item.root }}-{{ item.age }}</p>
        {% endfor %}
    </ul>


    {% if posts.has_previous %}
        <a href="?p={{ posts.previous_page_number }}">上一页</a>
        {% else %}
        <a href="#">上一页</a>
    {% endif %}

    <!--设置显示页码数-->
    {% for i in posts.paginator.pager_num_range %}
        {% if i == posts.number %}
            <a style='font-size: 30px' href="?p={{ i }}">{{ i }}</a>
        {% else %}
            <a href="?p={{ i }}">{{ i }}</a>
        {% endif %}
    {% endfor %}


    {% if posts.has_next %}
        <a href="?p={{ posts.next_page_number }}">下一页</a>
    {% endif %}


    <span>
        {{ posts.number }}/{{ posts.paginator.num_pages }}
    </span>

</body>
</html>

展示样例:

  • 四、自定义分页:

- 自定义模块 pager.py 文件,创建自定义类 Pagination(object)
- 传入参数:
  - 所有数据的总个数:models.xx.objects.all().count()
  - 当前页码
  - 每页显示条数:30
  - 最多显示页码数:7

  • 1、在所在应用文件夹里创建自定义模块 pager.py:

class Pagination(object):
    def __init__(self, totalCount, currentPage, perPageItemNum=10, maxPageNum=7):
        # 数据总个数
        self.total_count = totalCount

        # 当前页码数
        try:
            v = int(currentPage)
            if v <= 0:
                v = 1
            self.current_page = v
        except Exception as e:
            self.current_page = 1

        # 每页显示的条数
        self.per_page_item_num = perPageItemNum
        
        # 最多显示页码数
        self.max_page_num = maxPageNum

    # 计算展示数据切片开始值
    def start(self):
        return (self.current_page - 1) * self.per_page_item_num

    # 计算展示数据切片结束值
    def end(self):
        return self.current_page * self.per_page_item_num

    # 计算总页数
    @property
    def num_pages(self):
        """
        总数据条数666,每页10条,需要判断666除以10的余数是否为0
        如果余数为0,则总页数为商值
        如果余数不为0,则总页数为商值+1
        """
        a, b = divmod(self.total_count, self.per_page_item_num)

        if b == 0:
            return a
        else:
            return a + 1

    # 计算展示的页码范围
    def pager_num_range(self):
        # 总页数小于最多显示的页数,range范围取1到总页数+1(开区间所以得+1)
        if self.num_pages < self.max_page_num:  # 总页数3页,显示的页码数11页
            return range(1, self.num_pages + 1)  # 显示范围是 1-3页

        # 总页数特别多
        part = int(self.max_page_num / 2)  # 算出最多显示页码的一半,例如显示11页,此处就是5

        # 处理选择页码在1-5页的情况
        if self.current_page <= part:  # 当前页码 <= 显示页数的一半
            return range(1, self.max_page_num + 1)  # 显示范围是 1-11页

        # 处理选择页码在最后5页的情况
        if (self.current_page + part) > self.num_pages:  # 当前页+显示页数的一半 > 总页数
            return range(self.num_pages - self.max_page_num + 1, self.num_pages + 1)  # 显示范围是 (总页数-显示页数+1) 到 最后一页

        # 处理大多数中间页码的情况,例如当前页是第10页,显示范围是 5-15页
        return range(self.current_page - part, self.current_page + part + 1)  # 显示范围是  当前页-显示页码数的一半  到  当前页+显示页码数的一半

    # 自定义前端分页页码样式
    def page_str(self):
        # 创建一个空列表,用来保存各页码按钮样式的字符串
        page_list = []

        # 设置 "首页" 按钮
        first = "<li><a href='?p=1'>首页</a></li>"
        page_list.append(first)

        # 设置 "上一页" 按钮:当前页-1
        if self.current_page == 1:    # 当前页是第一页
            prev = "<li><a href='#'>上一页</a></li>"
        else:
            prev = "<li><a href='?p=%s'>上一页</a></li>" %(self.current_page-1)
        page_list.append(prev)

        # 设置中间页码按钮:
        for i in self.pager_num_range():
            # 设置当前页按钮样式:class='active'
            if i == self.current_page:
                temp = "<li class='active'><a href='?p=%s'>%s</a></li>" %(i,i)
            # 其他页码按钮样式:
            else:
                temp = "<li><a href='?p=%s'>%s</a></li>" % (i, i)
            page_list.append(temp)

        # 设置 "下一页" 按钮:当前页+1
        if self.current_page == self.num_pages:    # 当前页是最后一页
            nex = "<li><a href='#'>下一页</a></li>"
        else:
            nex = "<li><a href='?p=%s'>下一页</a></li>" % (self.current_page + 1)
        page_list.append(nex)

        # 设置 "尾页" 按钮
        last = "<li><a href='?p=%s'>尾页</a></li>" %(self.num_pages)
        page_list.append(last)

        return ''.join(page_list)
pager.py
  • 2、配置静态css样式文件 bootstrap:

  • 3、创建自定义分页 Pagination 对象,并传入参数:

from django.shortcuts import render
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger  # 导入django分页模块

# Create your views here.

# 模拟数据
USER_LIST = []

for i in range(1, 666):
    dic = {'root': 'root' + str(i), 'age': i}
    USER_LIST.append(dic)


def index3(request):
    from app01.pager import Pagination    # 导入自定义模块 pager.py 下的 Pagination 类

    # 获取当前页码
    current_page = request.GET.get('p')

    # 创建自定义分页类 Pagination 对象
    page_obj = Pagination(666, current_page, perPageItemNum=10, maxPageNum=7)

    # 输出展示数据的切片区间
    data_list = USER_LIST[page_obj.start(): page_obj.end()]
    return render(request, 'index3.html', {'data': data_list, 'page_obj': page_obj})

前端页面:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
</head>
<body>

    <ul>
        {% for item in data %}
            <p>{{ item.root }}-{{ item.age }}</p>
        {% endfor %}
    </ul>

    <!--引用自定义分页 Pagination 类中设置的页码样式-->
    <ul class="pagination pagination-sm">
        {{ page_obj.page_str|safe }}
    </ul>


</body>
</html>

展示样例:

 

总结,分页时需要做三件事:

  • 创建处理分页数据的类
  • 根据分页参数获取数据
  • 输出分页HTML,即:[上一页][1][2][3][4][5][下一页]

 

posted @ 2020-05-08 23:57  江畔何人初见月/  阅读(200)  评论(0)    收藏  举报