.. _topics-pagination: ========================= ペジネータ (paginator) ========================= :revision-up-to: 17812 (1.4) .. module:: django.core.paginator :synopsis: ページ分割されたデータを管理しやすくするためのクラスです。 Django は、ページ分割された (paginated) データを扱うためのペジネータ (paginator) クラスを提供しています。ページ分割とは、データが複数のページに わたって表示され、それぞれのページに「前へ/次へ」といったリンクがある状態 を指します。ペジネータのクラスは、 :file:`django/core/paginator.py` モジュー ルで定義されています。 使い方 ======= ペジネータを使うには、まず :class:`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 >>> 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`` をビューで使う ============================ 今度は、ビューの中でクエリセットをページ分割するために :class:`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}) テンプレート :file:`list.html` では、ページ間のナビゲーションを組み込みたいで しょう。ページはオブジェクトをもとにした何らかの興味深い情報を含んでいます:: {% for contact in contacts %} {# Each "contact" is a Contact model object. #} {{ contact.full_name|upper }}
... {% endfor %} .. versionchanged:: 1.4 以前は ``Page`` オブジェクトがイテレーション可能ではなかったので ``{% for contact in contacts.object_list %}`` とする必要がありました。 ``Paginator`` オブジェクト =========================== :class:`Paginator` クラスは、以下のようなコンストラクタを持っています: .. class:: Paginator(object_list, per_page, orphans=0, allow_empty_first_page=True) 必須の引数 ------------ ``object_list`` リスト、タプル、Django の ``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`` 例外を送出します。 メソッド --------- .. method:: Paginator.page(number) 指定ページの :class:`Page` オブジェクトを返します。ページ番号は 1 から 始まる数です。存在しないページを指定すると :exc:`InvalidPage` を送出し ます。 属性 ------ .. attribute:: Paginator.count 全てのページにわたるオブジェクトの合計数です。 .. note:: ``object_list`` に入っているオブジェクトの個数を調べるときに、 ``Paginator`` はまず ``object_list.count()`` を呼びます。 ``object_list`` に ``count()`` メソッドがなければ、 ``Paginator`` は ``len(object_list)`` に切り替えます。これにより、 ``QuerySet`` のようなオブジェクトで、より効率的な ``count()`` を呼 び出しているのです。 .. attribute:: Paginator.num_pages 総ページ数です。 .. attribute:: Paginator.page_range ``[1, 2, 3, 4]`` のように、 1 から始まるページ番号です。 ``InvalidPage`` 例外 ========================== .. exception:: InvalidPage ペジネータが不正なページ番号を渡された時に送出される例外の基底クラス です。 リクエストされたページが無効なページ (整数でないページ番号) であったり、ペー ジにオブジェクトが含まれていない場合、 :meth:`Paginator.page` メソッドは例外 を送出します。通常はこの ``InvalidPage`` 例外をトラップするだけですみますが、 より細かく例外処理するには、以下の例外をトラップしてください: .. exception:: PageNotAnInteger ``page()`` に整数でない値を渡したときに送出されます。 .. exception:: EmptyPage ``page()`` には有効な値が渡されているが、ページにオブジェクトが含まれな い場合に送出されます。 どちらの例外も :exc:``InvalidPage`` のサブクラスなので、単に ``except InvalidPage`` としておけば両方の例外を捕捉できます。 ``Page`` オブジェクト ===================== 普通は ``Page`` オブジェクトを手動で作ろうとは思わないでしょう。 :meth:`Paginator.page` を使って取得できます。 .. class:: Page(object_list, number, paginator): .. versionadded:: 1.4 ``len()`` を使ったり直接イテレーションする場合、ページは :attr:`Page.object_list` のように振る舞います。 メソッド --------- .. method:: Page.has_next() 次のページがある場合に ``True`` を返します。 .. method:: Page.has_previous() 前のページがある場合に ``True`` を返します。 .. method:: Page.has_other_pages() 前後 *いずれか* のページがある場合に ``True`` を返します。 .. method:: Page.next_page_number() 次のページが存在するかどうかに関係なく、「次のページ」のページ番号を返 します。 .. method:: Page.previous_page_number() 前のページが存在するかどうかに関係なく、「前のページ」のページ番号を返 します。 .. method:: Page.start_index() ページの先頭のオブジェクトの通番を、ペジネータ全体にわたるオブジェクト のリストの通番で返します。通番は 1 から始まります。例えば、ページあたり 2 個のオブジェクトを表示するペジネータで 5 個のオブジェクトをページ分割 している場合、2 ページ目の :meth:`~django.core.paginator.Paage.start_index` は ``3`` を返します。 .. method:: Page.end_index() ページの末尾のオブジェクトの通番を、ペジネータ全体にわたるオブジェクト のリストの通番で返します。通番は 1 から始まります。例えば、ページあたり 2 個のオブジェクトを表示するペジネータで 5 個のオブジェクトをページ分割 している場合、2 ページ目の :meth:`~django.core.paginator.end_index()` は ``4`` を返します。 属性 ------ .. attribute:: Page.object_list ページ上のオブジェクトのリストです。 .. attribute:: Page.number 1 から数えたページ番号です。 .. attribute:: Page.paginator ページの結びついている ``Paginator`` オブジェクトです。