• ページネーションの作り方を分かりやすく解説【原則をおさえるのがポイント】

    djangoは多くのデータを扱いますので、ページネーションを作りたいという場合もあるかもしれません。

    そこで今回は、ページネーションを作る方法を解説していきます。

    ページネーションを作るにはPaginatorクラスとPageクラスを使います

    djangoには、ページネーションを簡単に作ることができるように、PaginatorというクラスとPageというクラスがあらかじめ備えられています。

    ですので、ここからはこれら2つを使って、どうやってページネーションを作るのかをお伝えしていきます。

    Paginatorの使い方

    Paginatorの作り方はコードをみていった方がイメージがわきやすいと思いますので、コードを見ていきましょう。

    ベースコード(List,Detail)を使います。

    まずはpaginatorオブジェクトを作る

    まずはpaginatorオブジェクトを作ります。これは、Pagenatorクラスから作られるオブジェクトです。

    AppModelにデータが10個入っていると仮定しましょう。

    items = AppModel.objects.all()

    paginator = Paginator(itmes, 3)

    これでpaginaorオブジェクトができました。

    今回は、10という引数を使ってpaginatorオブジェクトを作りました。これは、ページネーションのページ区切りを10記事毎にするという意味です。

    つまり、今回はデータが10個ありますので、4ページからなるページネーションを作ったということになります。

    paginatorオブジェクトから、pagesオブジェクトを作る

    次に、paginatorオブジェクトからpagesオブジェクトを作っていきます。

    このpagesオブジェクトの中に、ページネーションオブジェクトを作る上で必要な情報が入っています。

    pagesオブジェクトを作るには、paginatorオブジェクトのpageメソッドを使います。

    pages = paginator.page(1)

    pageメソッドは最終的には、return Page(..)と、Pageクラスのオブジェクトを返すようになっていますので、pages = paginator.page()とすることでPageクラスから成るpagesオブジェクトを作ることができるのです。

    コードの整理

    ここまで書いてきたコードを改めて整理していきましょう。

    コード
    

    class appfunction(request):

        items = AppModel.objects.all()

        paginator = Paginator(items, 3)

        pages = paginator.page(1)

        return render(request, 'list.html', {'pages':pages}) 

    このようなコードになります。

    pagesオブジェクトでできること

    ここから、pagesオブジェクトでできることを紹介していきます。ここを見ると、具体的なページネーションのイメージがわいてくると思います。

    前提条件:データの数は10個、3個ずつ区切ったページネーションを作成、pagesオブジェクトの引数は1(1ページ目に関するデータ)

    入力 出力 説明
    pages <Page 1 of 4> 全ページと現在のページ
    pages.has_next() True 次のページがあるか
    pages.has_previous() False 前のページがあるか
    pages.has_other_pages() True 他のページがあるか
    pages.next_page_number() 2 次のページの番号
    pages.previous_page_number() エラー 前のページの番号
    pages.start_index 1 ページの先頭の記事番号
    pages.end_index 3 ページの最後の記事番号

    これらのデータをhtmlファイルに埋め込んでいくことによって、ページネーションを作ることができます。

    まずは簡単な表示をさせていきましょう。

    コード
    

    -list.html

    {{ pages.has_next }}

    {{ pages.next_page_number }}

     ブラウザではこのような表示になります。

    ページネーションの実装1

    次に、もう少しページネーションらしい形にしていきましょう。

    views.pyの調整

    今までは、pageは1に指定していましたが、これでは2ページ目をクリックしても、pagesオブジェクトに入るデータは1ページの情報になってしまいます。

    ページに応じてpagesオブジェクトに入れるデータを変えるために、views.pyファイルを整えていきましょう。

    具体的には、2ページ目をクリックしたら2ページ目の情報がpagesオブジェクトに入り、3ページ目をクリックしたら3ページ目の情報がpagesオブジェクトに入るようにします。

    コード
    

    class appfunction(request):

        items = AppModel.objects.all()

        paginator = Paginator(items, 3)

        page = request.GET.get('page', 1)

        pages = paginator.page(page)

       

    try:

            pages = paginator.page(page)

        except PageNotAnInteger:

            pages = paginator.page(1)

        except EmptyPage:

            pages = paginator.page(1)

     

        return render(request, 'list.html', {'pages':pages}) 

    request.GET.get('page', 1)で、urlに書かれているpageパラメータの数字を取るようにしています。もしurlにpageパラメータがなければ、1を返すようにしています。

    この点があまりよくわからない方は、request.getとrequest.GET.getの違いという記事を参考にしてみてください。

    また、try/except文では、pageのパラメーターがinteger型でない場合と、pageのパラメーターがページ数よりも大きい場合、1ページ目を出すように設定しています。

    これで、urlで指定したpageパラメーターに応じてpaginationオブジェクトに入れるデータを調整することができるようになりました。

    htmlファイルを整える

    最後に、htmlファイルを整えていきましょう。

    コード
    

    {% for item in pages %}

      <tr>

        <td>{{ item.title }}</td>

        <td>{{ item.content }}</td>

      </tr>

    {% endfor %}

     

    {% if users.has_other_pages %}

      <ul>

        {% if users.has_previous %}

          <li><a href="?page={{ users.previous_page_number }}">&laquo;</a></li>

        {% else %}

          <li class="disabled"><span>&laquo;</span></li>

        {% endif %}

        {% for i in users.paginator.page_range %}

          <li><a href="?page={{ i }}">{{ i }}</a></li>

        {% endfor %}

        {% if users.has_next %}

          <li><a href="?page={{ users.next_page_number }}">&raquo;</a></li>

        {% else %}

          <li><span>&raquo;</span></li>

        {% endif %}

      </ul>

    {% endif %}

    これでページネーションの実装ができました。

    ポイントは、最初のfor文です。{% for item in pages %}としており、pagesオブジェクトの中に、モデルのデータも入っていることを意識しておくとよいでしょう。

    ClassBasedViewで実装

    最後に、ClassvBasedViewでページネーションの実装を行っていきましょう。

    ClassBasedViewでのページネーションの実装はびっくりするほど簡単です。

    view.pyファイルをみていきましょう。

    コード
    

    class AppView(ListView):

        model = AppModel

        context_object_name = 'pages'

        paginated_by = 10

    これだけです。

    このように、pagenated_byを設定するだけで、pagesオブジェクトが使えるようになります。

    ~Django無料講義~のご案内

    Code for Djangoが、4時間超の無料Django講義をはじめました

    •  ・本を出版したCode for Djangoの
       製作者が作ったサイトです。
    •  ・Code for Djangoの内容も、
       動画で詳しく解説しています。
    •  ・動画は順次ふやしていきますので、
       ただで学び続けることが可能です。
    •  ・Djangoの効率的なスキルアップに、
       是非お役立て下さい。