Skip to main content

分页

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)  # `<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() # 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

注解

请注意,您可以使用 count()__len__() 方法为 Paginator 提供列表/元组,Django QuerySet 或任何其他对象。当确定包含在传递的对象中的对象的数量时,Paginator 将首先尝试调用 count(),然后回退到使用 len(),如果传递的对象没有 count() 方法。这允许诸如Django的 QuerySet 之类的对象在可用时使用更有效的 count() 方法。

在视图中使用 Paginator

这里有一个稍微复杂的例子,使用 Paginator 在一个视图中分页查询。我们同时给出视图和随附的模板,以显示如何显示结果。此示例假设您具有已导入的 Contacts 模型。

视图函数看起来像这样:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
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')
    try:
        contacts = paginator.page(page)
    except PageNotAnInteger:
        # If page is not an integer, deliver first page.
        contacts = paginator.page(1)
    except EmptyPage:
        # If page is out of range (e.g. 9999), deliver last page of results.
        contacts = paginator.page(paginator.num_pages)

    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={{ 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>
        {% endif %}
    </span>
</div>

Paginator 对象

Paginator 类有这个构造函数:

class Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True)[源代码]

必需参数

object_list

使用 count()__len__() 方法的列表,元组,QuerySet 或其他可切分对象。对于一致的分页,QuerySet 应当是有序的。在模型上使用 order_by() 子句或默认 ordering

性能问题分页大 QuerySet

如果您使用的 QuerySet 中包含大量项目,请求高页数在一些数据库上可能很慢,因为生成的 LIMIT/OFFSET 查询需要计算 OFFSET 记录的数量,该数量随着页面数量的增加而变长。

per_page

要包含在页面上的项目数量上限(不包括孤立项)(请参阅下面的 orphans 可选参数)。

可选参数

orphans

最后一页上允许的最少项目数,默认为零。当您不想拥有包含非常少的项目的最后一页时,使用此选项。如果最后一页将通常具有数项小于或等于 orphans,则这些项目将被添加到前一页(成为最后一页),而不是通过自己留下一个页面上的项目。例如,23项,per_page=10orphans=3,将有两页;第一页有10个项目,第二个(和最后一个)页面有13个项目。

allow_empty_first_page

第一页是否允许为空。如果 Falseobject_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]

Changed in Django 1.9:

在旧版本中,page_range 返回了一个列表而不是迭代器。

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()[源代码]

如果有下一个 or 上一页,则返回 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

属性

Page.object_list

此页面上的对象列表。

Page.number

此页面的基于1的页码。

Page.paginator

关联的 Paginator 对象。