Django自身提供了一些類來實現管理分頁,數據被分在不同的頁面中,並帶有“上一頁/下一頁”標簽。這個類叫做Pagination,其定義位於 django/core/paginator.py 中。
一. Paginator類的解釋
class Paginator(object): def __init__(self, object_list, per_page, orphans=0, allow_empty_first_page=True): self.object_list = object_list self.per_page = int(per_page) self.orphans = int(orphans) self.allow_empty_first_page = allow_empty_first_page self._num_pages = self._count = None
1.根據其定義做出以下解釋,上述代碼沒有將其類屬性和方法貼出。
- object_list:可以是列表,元組,查詢集或其他含有 count() 或 __len__()方法的可切片對象。對於連續的分頁,查詢集應該有序,例如有order_by()項或默認ordering參數。
- per_page:每一頁中包含條目數目的最大值,不包括獨立成頁的那頁。(見下面 orphans參數解釋)。
- orphans=0:當你使用此參數時說明你不希望最后一頁只有很少的條目。如果最后一頁的條目數少於等於orphans的值,則這些條目會被歸並到上一頁中(此時的上一頁變為最后一頁)。例如有23項條目, per_page=10,orphans=0,則有3頁,分別為10,10,3.如果orphans>=3,則為2頁,分別為10,13。
- allow_empty_first_page=True: 默認允許第一頁為空。
2.類方法:
- Paginator.page(number):根據參數number返回一個Page對象。(number為1的倍數)
3.類屬型:
- Paginator.count:所有頁面對象總數,即統計object_list中item數目。當計算object_list所含對象的數量時, Paginator會首先嘗試調用object_list.count()。如果object_list沒有 count() 方法,Paginator 接着會回退使用len(object_list)。
- Pagnator.num_pages:頁面總數。
- pagiator.page_range:頁面范圍,從1開始,例如[1,2,3,4]。
二. Page類的解釋
通常不用手動創建Page對象,可以從Paginator.page()來獲得他們。
class Page(collections.Sequence): def __init__(self, object_list, number, paginator): self.object_list = object_list self.number = number self.paginator = paginator
1.類方法
- Page.has_next() 如果有下一頁,則返回True。
- Page.has_previous() 如果有上一頁,返回 True。
- Page.has_other_pages() 如果有上一頁或下一頁,返回True。
- Page.next_page_number() 返回下一頁的頁碼。如果下一頁不存在,拋出InvlidPage異常。
- Page.previous_page_number() 返回上一頁的頁碼。如果上一頁不存在,拋出InvalidPage異常。
- Page.start_index() 返回當前頁上的第一個對象,相對於分頁列表的所有對象的序號,從1開始。比如,將五個對象的列表分為每頁兩個對象,第二頁的start_index()會返回3。
- Page.end_index() 返回當前頁上的最后一個對象,相對於分頁列表的所有對象的序號,從1開始。 比如,將五個對象的列表分為每頁兩個對象,第二頁的end_index() 會返回 4。
2.類屬型
- Page.object_list 當前頁上所有對象的列表。
- Page.number 當前頁的序號,從1開始。
- Page.paginator 相關的Paginator對象。
三.非法頁面處理
-
- InvalidPage(Exception): 異常的基類,當paginator傳入一個無效的頁碼時拋出。
Paginator.page()放回在所請求的頁面無效(比如不是一個整數)時,或者不包含任何對象時拋出異常。通常,捕獲InvalidPage異常就夠了,但是如果你想更加精細一些,可以捕獲以下兩個異常之一:
- exception PageNotAnInteger,當向page()提供一個不是整數的值時拋出。
- exception EmptyPage,當向page()提供一個有效值,但是那個頁面上沒有任何對象時拋出。
這兩個異常都是InalidPage的子類,所以可以通過簡單的except InvalidPage來處理它們。
四.使用Paginator
官方示例:
views.py:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from django.shortcuts import render def listing(request): contact_list = Contacts.objects.all() # 獲取所有contacts,假設在models.py中已定義了Contacts模型 paginator = Paginator(contact_list, 25) # 每頁25條
page = request.GET.get('page') try: contacts = paginator.page(page) # contacts為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>
final: 根據官方示例代碼結果如下,頁面共有3頁,首頁時只有next選項,中間頁時可選擇previous 或 next,尾頁時只有previous選項。


另:給出另一種list.html:
<div id="pagination">
<ul id="pagination-flickr"> {% if article_list.has_previous %} <li class="previous"><a href="?page={{ article_list.previous_page_number }}{% if request.GET.year %}&year={{ request.GET.year }}{% endif %}{% if request.GET.month %}&month={{ request.GET.month }}{% endif %}{% if request.GET.cid %}&cid={{ request.GET.cid }}{% endif %}">«上一頁</a></li> {% else %} <li class="previous-off">«上一頁</li> {% endif %} <li class="active">{{ article_list.number }}/{{ article_list.paginator.num_pages }}</li> {% if article_list.has_next %} <li class="next"><a href="?page={{ article_list.next_page_number }}{% if request.GET.year %}&year={{ request.GET.year }}{% endif %}{% if request.GET.month %}&month={{ request.GET.month }}{% endif %}{% if request.GET.cid %}&cid={{ request.GET.cid }}{% endif %}">下一頁 »</a></li> {% else %} <li class="next-off">下一頁 »</li> {% endif %} </ul>
</div>
contacts 和 article_list 是同一個意思,效果如下:

