Django專門提供了一個paginator模塊,實現分頁很easy。
下面的例子引用了django官方文檔:https://docs.djangoproject.com/en/1.11/topics/pagination/
使用Paginator類
Paginator實例化需要2個參數,一個是待分頁的對象list(需要實現count方法或者__len__方法),另一個是每頁數量。
Paginator對象屬性:
count 對象數量
num_pages 總頁數
page_range 所有頁數范圍的生成器
>>> 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)
Paginator對象的重要方法,page(),接受一個頁碼作為參數,返回一個當前頁對象。該對象的幾個屬性和方法:
object_list 當前頁的對象列表
has_next() 有無下一頁
has_ previous() 有無上一頁
has_other_pages() 有無其他頁
next_page_number() 下一頁頁碼
previous_page_number() 上一頁頁碼
start_index() 返回當前頁第一個對象的在所有對象中的索引,注意,從1開始
end_index() 返回當前頁最后一個對象在所有對象中的索引,注意,從1開始
paginator 所關聯的Paginator對象
>>> 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
Pagenator的page方法,若傳給一個無頁碼范圍之外都值,則得到一個EmptyPage的異常。
>>> 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
在視圖中可以這么用:
# views.py 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) # 每頁顯示25個 page = request.GET.get('page') # 拿到頁碼參數 try: contacts = paginator.page(page) except PageNotAnInteger: # 捕獲到頁碼不是整數,返回第一頁 contacts = paginator.page(1) except EmptyPage: # 頁碼超出范圍,返回最后一頁 contacts = paginator.page(paginator.num_pages) return render(request, 'list.html', {'contacts': contacts})
contacts對象是用帶有分頁信息的QuerySet,用來渲染模板: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>
基於模型類的視圖,只需給paginate_by賦值(每頁個數)就可以了,似乎是更簡單:
class BookListView(generic.ListView): model = Book context_object_name = 'book_list' template_name = 'catalog/book_list.html' paginate_by = 10
模板是通用的,在模板中,可以調用is_paginated 判斷是否有分頁信息。在用page_obj對象實現分頁。
{% block pagination %} {% if is_paginated %} <div class="pagination"> <span class="pagelinks"> {% if page_obj.has_previous %} <a href="{{ request.path }}?page={{ page_obj.previous_page_number }}">previous</a> {% endif %} <span class="page-current"> Page{{ page_obj.number }} of {{ page_obj.paginator.num_pages }}. </span> {% if page_obj.has_next %} <a href="{{ request.path }}?page={{ page_obj.next_page_number }}">next</a> {% endif %} </span> </div> {% endif %} {% endblock %}