revision-up-to: | 17812 (1.4) |
---|
Django は、ページ分割された (paginated) データを扱うためのペジネータ
(paginator) クラスを提供しています。ページ分割とは、データが複数のページに
わたって表示され、それぞれのページに「前へ/次へ」といったリンクがある状態
を指します。ペジネータのクラスは、 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
>>> p.page_range
[1, 2]
>>> 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()
3
>>> 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
Note
Paginator
にはリストやタプル、 Django の QuerySet
の他に、
count()
や __len__()
をメソッドを備えた任意のオブジェクトを渡せ
ることに注意してください。 Paginator
は、渡されたコンテナ内のオブジェ
クトの数を調べるのに、まず count()
を呼び出そうとし、 count()
がなければ len()
にフォールバックします。これにより、 QuerySet
のようなオブジェクトで、より効率的な count()
を呼び出しています。
Paginator
をビューで使う¶今度は、ビューの中でクエリセットをページ分割するために Paginator
を
使うもう少し複雑な例です。どのように結果が表示されるかが分かるように、ビュー
とビューが使うテンプレートの両方を示します。この例では Contacts
モデルが
既にインポートされているものとします。
ビュー関数は以下のようになります:
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
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_to_response('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>
Page
オブジェクトがイテレーション可能ではなかったので
{% for contact in contacts.object_list %}
とする必要がありました。Paginator
オブジェクト¶Paginator
クラスは、以下のようなコンストラクタを持っています:
Paginator
(object_list, per_page, orphans=0, allow_empty_first_page=True)¶object_list
QuerySet
, または count()
や
__len__()
メソッドを備えたオブジェクトを指定します。per_page
orphans
も参照してください)。orphans
orphans
を設定すると、ページ分割した要素の末尾のグ
ループの個数が orphans
の設定値以下のときに、そのグループの要素だけ
のページを表示するのではなく、ひとつ前のページの要素に繰り入れて表示し
ます(すなわち、一つ手前のページが最終ページになります)。例えば、
per-page=10
かつ orphans=3
のペジネータで 23 個のオブジェクトを
表示すると、ページは二つに分割され、最初のページには 10 個、二つ目のペー
ジ(最終ページ)には 13 個の要素を表示します。allow_empty_first_page
False
に設定
すると、 object_list
が空のときに EmptyPage
例外を送出します。Paginator.
page
(number)¶指定ページの Page
オブジェクトを返します。ページ番号は 1 から
始まる数です。存在しないページを指定すると InvalidPage
を送出し
ます。
Paginator.
count
¶全てのページにわたるオブジェクトの合計数です。
Note
object_list
に入っているオブジェクトの個数を調べるときに、
Paginator
はまず object_list.count()
を呼びます。
object_list
に count()
メソッドがなければ、 Paginator
は len(object_list)
に切り替えます。これにより、
QuerySet
のようなオブジェクトで、より効率的な count()
を呼
び出しているのです。
Paginator.
num_pages
¶総ページ数です。
Paginator.
page_range
¶[1, 2, 3, 4]
のように、 1 から始まるページ番号です。
InvalidPage
例外¶InvalidPage
¶ペジネータが不正なページ番号を渡された時に送出される例外の基底クラス です。
リクエストされたページが無効なページ (整数でないページ番号) であったり、ペー
ジにオブジェクトが含まれていない場合、 Paginator.page()
メソッドは例外
を送出します。通常はこの InvalidPage
例外をトラップするだけですみますが、
より細かく例外処理するには、以下の例外をトラップしてください:
PageNotAnInteger
¶page()
に整数でない値を渡したときに送出されます。
EmptyPage
¶page()
には有効な値が渡されているが、ページにオブジェクトが含まれな
い場合に送出されます。
どちらの例外も :exc:InvalidPage
のサブクラスなので、単に
except InvalidPage
としておけば両方の例外を捕捉できます。
Page
オブジェクト¶普通は Page
オブジェクトを手動で作ろうとは思わないでしょう。
Paginator.page()
を使って取得できます。
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
()¶次のページが存在するかどうかに関係なく、「次のページ」のページ番号を返 します。
Page.
previous_page_number
()¶前のページが存在するかどうかに関係なく、「前のページ」のページ番号を返 します。
Page.
start_index
()¶ページの先頭のオブジェクトの通番を、ペジネータ全体にわたるオブジェクト
のリストの通番で返します。通番は 1 から始まります。例えば、ページあたり
2 個のオブジェクトを表示するペジネータで 5 個のオブジェクトをページ分割
している場合、2 ページ目の
start_index()
は 3
を返します。
Page.
end_index
()¶ページの末尾のオブジェクトの通番を、ペジネータ全体にわたるオブジェクト
のリストの通番で返します。通番は 1 から始まります。例えば、ページあたり
2 個のオブジェクトを表示するペジネータで 5 個のオブジェクトをページ分割
している場合、2 ページ目の end_index()
は 4
を返します。
Oct 26, 2017