Djangoの投稿一覧ページにページネーションを実装する方法

Django側で予めページネーション用のパッケージ、django.core.paginator を用意してくれています。

例として MyModel というモデルのインスタンスを一覧表示し、ページネーションを導入します。

from django.core.paginator import Paginator
from django.views.generic import ListView

from .models import MyModel

class MyModelListView(ListView):
    model = MyModel
    paginate_by = 10  # 1ページあたりの表示数

    def get_queryset(self):
        queryset = super().get_queryset()
        # このメソッドでクエリセットを加工することができます。
        return queryset.order_by('-created_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        paginator = context['paginator']
        page_numbers_range = 10  # ページ番号の表示数
        max_index = len(paginator.page_range)
        page = self.request.GET.get('page')
        current_page = int(page) if page else 1

        start_index = int((current_page - 1) / page_numbers_range) * page_numbers_range
        if start_index + page_numbers_range > max_index:
            end_index = max_index
        else:
            end_index = start_index + page_numbers_range

        context['page_numbers'] = paginator.page_range[start_index:end_index]
        return context

get_queryset メソッドで、モデルのクエリセットを加工しています。ここでは、 created_at フィールドで並び替えていますが、必要に応じて変更してください。

また、 get_context_data メソッドで、テンプレートに渡すデータに、ページ番号を含めています。

テンプレートでのページ番号の表示方法は、以下のようになります。

{% if page_obj.has_previous %}
    <a href="?page={{ page_obj.previous_page_number }}">前へ</a>
{% endif %}
{% for i in page_numbers %}
    {% if page_obj.number == i %}
        <strong>{{ i }}</strong>
    {% else %}
        <a href="?page={{ i }}">{{ i }}</a>
    {% endif %}
{% endfor %}
{% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}">次へ</a>
{% endif %}

page_obj は、 get_context_data メソッドで追加した Page オブジェクトです。

このオブジェクトには、現在のページや前後のページの情報が含まれています。

このエントリーをはてなブックマークに追加

コメントを残す

頂いたコメントは一読した後表示させて頂いております。
反映まで数日かかる場合もございますがご了承下さい。