分页 — Django 文档
分页
Django 提供了一些类来帮助您管理分页数据——也就是说,数据被分成多个页面,带有“上一页/下一页”链接。 这些类位于 django/core/paginator.py
。
示例
给 Paginator 一个对象列表,加上你希望在每个页面上拥有的项目数量,它为你提供了访问每个页面项目的方法:
>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)
>>> p.count
4
>>> p.num_pages
2
>>> type(p.page_range)
<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() # The 1-based index of the first item on this page
3
>>> page2.end_index() # The 1-based index of the last item on this page
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
笔记
请注意,您可以给 Paginator
一个列表/元组、一个 Django QuerySet
或任何其他具有 count()
或 __len__()
方法的对象。 在确定传递的对象中包含的对象数量时,Paginator
将首先尝试调用 count()
,如果传递的对象没有 count()
,则回退到使用 len()
] 方法。 这允许诸如 Django 的 QuerySet
之类的对象在可用时使用更高效的 count()
方法。
在视图中使用 Paginator
这是一个稍微复杂的示例,它使用 Paginator 在视图中对查询集进行分页。 我们提供了视图和随附的模板来展示如何显示结果。 此示例假设您有一个已导入的 Contacts
模型。
视图函数如下所示:
from django.core.paginator import Paginator
from django.shortcuts import render
def listing(request):
contact_list = Contacts.objects.all()
paginator = Paginator(contact_list, 25) # Show 25 contacts per page
page = request.GET.get('page')
contacts = paginator.get_page(page)
return render(request, 'list.html', {'contacts': contacts})
在模板 list.html
中,您需要包含页面之间的导航以及来自对象本身的任何有趣信息:
{% for contact in contacts %}
{# Each "contact" is a Contact model object. #}
{{ contact.full_name|upper }}<br>
...
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if contacts.has_previous %}
<a href="?page=1">« first</a>
<a href="?page={{ contacts.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ contacts.number }} of {{ contacts.paginator.num_pages }}.
</span>
{% if contacts.has_next %}
<a href="?page={{ contacts.next_page_number }}">next</a>
<a href="?page={{ contacts.paginator.num_pages }}">last »</a>
{% endif %}
</span>
</div>
Paginator 物体
Paginator 类有这个构造函数:
- class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)
必需参数
object_list
列表、元组、
QuerySet
或其他具有count()
或__len__()
方法的可切片对象。 为了一致的分页,应该订购QuerySet
s,例如 使用 order_by() 子句或模型上的默认 ordering。分页大
QuerySet
的性能问题如果您使用包含大量项目的
QuerySet
,则在某些数据库上请求高页码可能会很慢,因为生成的LIMIT
/OFFSET
查询需要计算OFFSET
记录的数量,随着页码变高,这需要更长的时间。per_page
页面上包含的最大项目数,不包括孤立项目(请参阅下面的
orphans
可选参数)。
可选参数
orphans
- 当您不希望最后一页的项目很少时,请使用此选项。 如果最后一页的项目数通常小于或等于
orphans
,那么这些项目将被添加到上一页(成为最后一页),而不是将这些项目单独留在页面上. 例如,有23个条目,per_page=10
和orphans=3
,就会有两个页面; 第一页有 10 个项目,第二页(也是最后一个)有 13 个项目。orphans
默认为零,这意味着页面永远不会合并,最后一页可能有一个项目。 allow_empty_first_page
- 是否允许第一页为空。 如果
False
和object_list
为空,则会引发EmptyPage
错误。
方法
- Paginator.get_page(number)
返回具有给定的基于 1 的索引的 Page 对象,同时还处理超出范围和无效页码。
如果页面不是数字,则返回第一页。 如果页码为负数或大于页数,则返回最后一页。
仅当您指定
Paginator(..., allow_empty_first_page=False)
且object_list
为空时,它才会引发异常 (EmptyPage)。
- Paginator.page(number)
- 返回具有给定的基于 1 的索引的 Page 对象。 如果给定的页码不存在,则引发 InvalidPage。
属性
- Paginator.count
跨所有页面的对象总数。
笔记
在确定
object_list
中包含的对象数量时,Paginator
将首先尝试调用object_list.count()
。 如果object_list
没有count()
方法,那么Paginator
将回退到使用len(object_list)
。 这允许对象,例如 Django 的QuerySet
,在可用时使用更有效的count()
方法。
- Paginator.num_pages
- 总页数。
- Paginator.page_range
- 页码的基于 1 的范围迭代器,例如 产生
[1, 2, 3, 4]
。
InvalidPage 异常
- exception InvalidPage
- 当分页器传递无效页码时引发异常的基类。
Paginator.page() 如果请求的页面无效(即,不是整数)或不包含任何对象,则该方法会引发异常。 通常,捕获 InvalidPage
异常就足够了,但如果您想要更细化,则可以捕获以下任一异常:
- exception PageNotAnInteger
- 当
page()
被赋予一个不是整数的值时引发。
- exception EmptyPage
- 当
page()
被赋予有效值但该页面上不存在对象时引发。
这两个异常都是 InvalidPage 的子类,因此您可以使用简单的 except InvalidPage
处理它们。
Page 物体
您通常不会手动构建 Page
对象——您将使用 Paginator.page() 来获取它们。
- class Page(object_list, number, paginator)
- 当使用
len()
或直接对其进行迭代时,页面的作用类似于 Page.object_list 的序列。
方法
- Page.has_next()
- 如果有下一页,则返回
True
。
- Page.has_previous()
- 如果有上一页,则返回
True
。
- Page.has_other_pages()
- 如果有下一页 或 上一页,则返回
True
。
- Page.next_page_number()
- 返回下一个页码。 如果下一页不存在,则引发 InvalidPage。
- Page.previous_page_number()
- 返回上一个页码。 如果上一页不存在,则引发 InvalidPage。
- Page.start_index()
- 返回页面上第一个对象的从 1 开始的索引,相对于分页器列表中的所有对象。 例如,当用每页 2 个对象对 5 个对象的列表进行分页时,第二页的 start_index() 将返回
3
。
- Page.end_index()
- 返回页面上最后一个对象的从 1 开始的索引,相对于分页器列表中的所有对象。 例如,当用每页 2 个对象对 5 个对象的列表进行分页时,第二页的 end_index() 将返回
4
。