DjangoのListViewクラスを使って一覧ページを作る時、htmlファイルにページネーションを作成する事が多いと思います。今回は私がよく使う使い勝手の良いページネーション用のhtmlコードを紹介します。
サンプルコード
以下がサンプルコードです。※Bootstrapのclassを使用しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | {% load core_tags %} {% if page_obj.has_previous or page_obj.has_next %} < nav > < ul class = "pagination" > {% if page_obj.has_previous %} < li class = "page-item" > < a class = "page-link" href = '{{ request.path }}?page=1{{ request.GET.items|get_search_query_param }}' > < span >最初</ span > </ a > </ li > < li class = "page-item" > < a class = "page-link" href = '{{ request.path }}?page={{ page_obj.previous_page_number }}{{ request.GET.items|get_search_query_param }}' >{{ page_obj.previous_page_number }}</ a > </ li > {% else %} < li class = "page-item disabled" > < a class = "page-link" > < span >最初</ span > </ a > </ li > {% endif %} < li class = "page-item active" > < a class = "page-link" href = '{{ request.path }}?page={{ page_obj.number }}{{ request.GET.items|get_search_query_param }}' >{{ page_obj.number }}</ a > </ li > {% if page_obj.has_next %} < li class = "page-item" > < a class = "page-link" href = '{{ request.path }}?page={{ page_obj.next_page_number }}{{ request.GET.items|get_search_query_param }}' >{{ page_obj.next_page_number }}</ a > </ li > < li class = "page-item" > < a class = "page-link" href = '{{ request.path }}?page={{ paginator.num_pages }}{{ request.GET.items|get_search_query_param }}' > < span >最後</ span > </ a > </ li > {% else %} < li class = "page-item disabled" > < a class = "page-link" > < span >最後</ span > </ a > </ li > {% endif %} </ ul > </ nav > {% endif %} |
条件
このサンプルコードは以下の条件を満たすViewクラスを使用している必要があります。
- ListViewクラスを継承している
- paginate_byを定義している
読み込み方法
上記のコードをpagination.htmlとして保存します。ページネーションを追加したいhtmlファイルに、includeを使って以下のように読み込ませます。
1 | {% include 'pagination.html' %} |
‘pagination.html’部分はファイルパスに応じて適宜変更してください。
表示例
1ページしかない場合はページネーションを表示しません。
複数ページある場合は表示しているページにより表示が変わります。
1ページ目を表示している場合

最初のページを表示している場合は’最初’の部分はクリックできないようにしています。該当コードを削除すれば非表示にすることもできます。
中間のページを表示している場合

表示しているページの前後のページを表示しています。
最後のページを表示している場合

1ページ目を表示している場合と同様です。
解説
1 | {% load core_tags %} |
独自実装したテンプレートタグを読み込んでいます。今回はファイル名をcore_tags.pyとします。
1 | {% if page_obj.has_previous or page_obj.has_next %} |
1ページのみか複数ページあるかどうかを判定しています。
1 | < a class = "page-link" href = '{{ request.path }}?page={{ page_obj.previous_page_number }}{{ request.GET.items|get_search_query_param }}' > |
{{ request.path }}
現在のURLを取得しています。
{{ page_obj.previous_page_number }}
前のページ数を取得しています。他のaタグでは後ろのページ数や最後のページ数を取得する変数を指定しています。
{{ request.GET.items|get_search_query_param }}
request.GET.itemsにはクエリパラメーターが辞書形式で定義されています。検索条件を指定できるページの場合、クエリパラメータを指定する必要がありあます。
クエリパラメーターの中には現在のページ数を表す’page’パラメーターがあります。’page’はListViewクラスで表示したいページ数を取得するためのキーとして定義されています。
1 | page_kwarg = "page" |
ページネーションで’page’パラメーターを個別で指定したいため、’page’パラメーターを除くクエリパラメーターを取得するためのテンプレートタグを定義する必要があります。
テンプレートタグを定義するcore_tags.pyに以下の関数を作成します。
1 2 3 4 5 6 7 | @register . filter def get_search_query_param(value): result = '' for k, v in value: if k ! = 'page' : result + = f '&{k}={v}' return result |
処理速度を重視したい場合はViewクラス内で定義すると良いです(その場合はデコレーターは不要です)
応用編 表示数をクエリパラメーターで指定する
ユーザーが表示数を変更できるタイプのサイトはよくあります。
応用編としてデフォルトの表示数が10、指定可能な表示数が10~100のページに対応したページネーションを作成する方法を解説します。
表示数を動的に変更したい場合は次のようにget_paginate_by()をオーバーライドします。ここではpage_sizeというクエリパラメーターを使う想定です。
1 2 3 4 5 6 | def get_paginate_by( self , queryset): page_size = self .request.GET.get( 'page_size' , 10 ) try : return page_size if 10 < = int (page_size) < = 100 else 10 except ValueError: return 10 |
この場合、テンプレートタグは次のようにpage_sizeも除外するように改変します。
1 2 3 4 5 6 7 | @register . filter def get_search_query_param(value): result = '' for k, v in value: if k not in [ 'page' , 'page_size' ]: result + = f '&{k}={v}' return result |
aタグのhrefにpage_sizeのクエリパラメーターを追加します。{{paginator.per_page}}で現在の表示数を取得できます。
1 | href='{{ request.path }}?page={{ page_obj.previous_page_number }}&page_size={{paginator.per_page}}{{ request.GET.items|get_search_query_param }} |
まとめ
ListView関数やPaginationクラスは非常に便利ですが、ページネーション用のhtmlは独自実装する必要があります。
今回紹介したサンプルはどのURLでも対応しています。最初のページ、前後のページ、最後のページへのリンクの作成方法や、クエリパラメーターを保持する方法も紹介しているのでアレンジしやすいと思います。