为什么要分页

分页功能是几乎所有的网站上都需要提供的功能,当你要展示的条目比较多时,必须进行分页,不但能减小数据库读取数据压力,也有利于用户浏览。

原生方法分页

  1. 在urls.py里urlpatterns中添加
    path('getstudents/', views.get_students, name='get_students'),
  2. views.py中添加get_students函数获取学生数量
    1
    2
    3
    4
    5
    6
    7
    8
    def get_students(request):
    page = int(request.GET.get("page", 1))
    per_page = int(request.GET.get("per_page", 10))
    students = Student.objects.all()[per_page*(page-1): page*per_page]
    data = {
    "students": students
    }
    return render(request, 'students.html', context=data)
  3. 通过访问http://127.0.0.1:8001/app/getstudents/?page=2&per_page=20可以看到分页效果

分页器Paginator

Django很贴心的为我们提供了一个Paginator分页工具。分页功能位于django.core.paginator模块。

API

Paginator提供包含一些对象的列表,以及你想每一页显示几条,比如每页5条、10条、20条、100条等等,它就会为你提供访问的一系列API方法,示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2) # 对objects进行分页,虽然objects只是个字符串列表,但没关系,一样用。每页显示2条。

>>> p.count # 对象个数
4
>>> p.num_pages # 总共几页
2
>>> type(p.page_range) # `<type 'rangeiterator'>` in Python 2.
<class 'range_iterator'>
>>> p.page_range # 分页范围
range(1, 3)

>>> page1 = p.page(1) # 获取第一页
>>> page1
<Page 1 of 2>
>>> page1.object_list # 获取第一页的对象
['john', 'paul']

>>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next() # 判断是否有下一页
False
>>> page2.has_previous()# 判断是否有上一页
True
>>> page2.has_other_pages() # 判断是否有其它页
True
>>> page2.next_page_number() # 获取下一页的页码
Traceback (most recent call last):
...
EmptyPage: That page contains no results
>>> page2.previous_page_number() # 获取上一页的页码
1
>>> page2.start_index() # 从1开始计数的当前页的第一个对象
3
>>> page2.end_index() # 从1开始计数的当前页最后1个对象
4

>>> p.page(0) # 访问不存在的页面
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1
>>> p.page(3) # 访问不存在的页面
Traceback (most recent call last):
...
EmptyPage: That page contains no results

实例

  1. 在urls.py里urlpatterns中添加
    path('getstudentswithpage/', views.get_students_with_page, name='get_students_with_page')
  2. views.py中添加getstudentswithpage函数获取学生数量
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 分页器
    def get_students_with_page(request):

    page = int(request.GET.get("page", 1))
    per_page = int(request.GET.get("per_page", 10))

    students = Student.objects.all()
    paginator = Paginator(students, per_page)
    page_object = paginator.page(page)
    data = {
    "page_object": page_object,
    "page_range": paginator.page_range
    }
    return render(request, 'students_with_page.html', context=data)
  3. 绘制students_with_page.html界面
    包括前一页、下一页、边缘bug处理
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>students_with_page</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
    integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
    </head>
    <body>
    <ul>
    {% for student in page_object.object_list %}
    <li>{{ student.s_name }}</li>
    {% endfor %}
    </ul>

    <nav aria-label="Page navigation">
    <ul class="pagination">
    {% if page_object.has_previous %}
    <li class="page-item">
    <a class="page-link"
    href="{% url 'app:get_students_with_page' %}?page={{ page_object.previous_page_number }}"
    aria-label="Previous">
    <span aria-hidden="true">&laquo;</span>
    </a>
    </li>
    {% else %}
    <li class="disabled">
    <a class="page-link"
    href="#"
    aria-label="Previous">
    <span aria-hidden="true">&laquo;</span>
    </a>
    </li>
    {% endif %}

    {% for page_index in page_range %}
    {% ifequal page_index page_object.number %}
    <li class="active"><a class="page-link"
    href="{% url 'app:get_students_with_page' %}?page={{ page_index }}">{{ page_index }}</a></li>
    {% else %}
    <li><a class="page-link"
    href="{% url 'app:get_students_with_page' %}?page={{ page_index }}">{{ page_index }}</a></li>
    {% endifequal %}
    {% endfor %}

    {% if page_object.has_next %}
    <li class="page-item">
    <a class="page-link"
    href="{% url 'app:get_students_with_page' %}?page={{ page_object.next_page_number }}"
    aria-label="Next">
    <span aria-hidden="true">&raquo;</span>
    </a>

    {% else %}
    <li class="disabled">
    <a class="page-link" href="#" aria-label="Next">
    <span aria-hidden="true">&raquo;</span>
    </a>
    </li>
    {% endif %}

    </ul>
    </nav>
    </body>
    </html>
  4. 通过访问http://127.0.0.1:8001/app/getstudentswithpage/?page=1&per_page=10可以如下图图看到第五页分页,
    可以进行简单的前一页,下一页操作!

第五页