背景
- 1画面に表示する件数が多かったので、ページネーションを追加する。
- 標準の
django.core.paginator
を使う - 環境は、Python 3.7.0 + Django 2.1.3
既存のコードの変更
views.pyの変更
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
を追加ページネーション用の関数を追加
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
# ページネーション用に、Pageオブジェクトを返す。
def paginate_query(request, queryset, count):
paginator = Paginator(queryset, count)
page = request.GET.get('page')
try:
page_obj = paginator.page(page)
except PageNotAnInteger:
page_obj = paginator.page(1)
except EmptyPage:
page_obj = paginatot.page(paginator.num_pages)
return page_obj
- リクエストを受け取る関数の変更
def myapp1(request):
series = Series.objects.filter(deleted = False).order_by('-created_at')
page_obj = paginate_query(request, series, settings.PAGE_PER_ITEM) # ページネーション
return render(request, 'app1/index.html', {'page_obj': page_obj, 'site_name':settings.SITE_NAME}) # モデルから取得したobjectsの代わりに、page_objを渡す
テンプレートの変更
- モデルから取得したobjectsの代わりに、page_objを使って表示。
{% for s in series %}
<p>{{ s.title }}</p>
{% endfor %}
を、seriesをpage_objに置き換える(for文の中身はそのままでよい)
{% for s in page_obj %}
<p>{{ s.title }}</p>
{% endfor %}
- ページネーション部分を追加(別ファイルに作成して、includeするとよい)
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">« first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last »</a>
{% endif %}
</span>
</div>
設定ファイルに、1ページに表示する件数を指定
PAGE_PER_ITEM = 15
Bootstrap4を使って見映えをよくする
- for文用のページ番号のリストを得るために、
page_obj.paginator.page_range
を使う - 他は、
has_previous
,previous_page_number
,has_next
,next_page_number
,number
で指定する
<div>
<nav aria-label="Page navigation example">
<ul class="pagination">
{% if page_obj.has_previous %}
<li><a class="page-link text-primary d-inline-block" href="?page={{ page_obj.previous_page_number }}">前</a></li>
{% else %}
<li class="disabled"><div class="page-link text-secondary d-inline-block disabled" href="#">前</div></li>
{% endif %}
{% for link_page in page_obj.paginator.page_range %}
{% if link_page %}
{% if link_page == page_obj.number %}
<li class="disabled"><div class="page-link text-secondary d-inline-block disabled" href="#">{{ link_page }}</div></li>
{% else %}
<li><a class="page-link text-primary d-inline-block" href="?page={{ link_page }}">{{ link_page }}</a></li>
{% endif %}
{% else %}
<li class="disabled"><a class="page-link text-secondary d-inline-block text-muted" href="#">・・・</a></li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li><a class="page-link text-primary d-inline-block" href="?page={{ page_obj.next_page_number }}">次</a></li>
{% else %}
<li class="disabled"><div class="page-link text-secondary d-inline-block disabled" href="#">次</div></li>
{% endif %}
</ul>
</nav>
</div>
- このような見映えになります。
参考ページ
- 公式ドキュメントのページネーション – Page オブジェクト
- Django、ページング処理まとめ
- DjangoでPaginationを実装する
- Bootstrap4の公式ページのPagination