【Django入門26】ページネーションの実装|大量データを効率的に表示する方法

ページネーションとは?

ページネーションの概要

ページネーションとは、大量のデータを複数ページに分割して表示する仕組みです。Webアプリケーションでは、ブログの記事一覧、商品一覧、コメント一覧など、表示するデータが多い場合にページネーションがよく使われます。

なぜページネーションが重要なのか?

  • ユーザビリティの向上:一度に大量の情報を表示すると、ユーザーが見づらくなります。ページネーションを使うことで、情報を整理して見やすくできます。
  • パフォーマンスの向上:すべてのデータを一度に取得するのではなく、必要なデータだけを取得することで、サーバー負荷を軽減します。
  • ナビゲーションの提供:ユーザーが前後のページに簡単に移動できるようになります。

Djangoでのページネーションの基本設定

必要なパッケージとモジュール

Djangoにはページネーション機能が標準で用意されています。特に追加のパッケージをインストールする必要はありません。

使用する主なモジュールは以下の通りです:

  • django.core.paginator.Paginator:データの分割を行うクラス。
  • Pageオブジェクト:現在のページ情報を保持し、ページナビゲーションに必要な情報を提供します。

ページネーションの実装手順

モデルの作成

まず、ページネーションを行うデータを格納するためのモデルを作成します。

models.py:

from django.db import models

class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    published_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title
  • title: 記事のタイトル。
  • content: 記事の内容。
  • published_at: 記事の公開日時。

ダミーデータの作成

次に、開発環境でテストするためにダミーデータを作成します。

シェルでのダミーデータ作成:

python manage.py shell
from myapp.models import Article

for i in range(1, 51):
    Article.objects.create(title=f"記事 {i}", content="これはサンプルの記事です。")

ビューの作成

データをページごとに分割し、テンプレートに渡すビューを作成します。

views.py:

from django.core.paginator import Paginator
from django.shortcuts import render
from .models import Article

def article_list_view(request):
    articles = Article.objects.all().order_by('-published_at')
    paginator = Paginator(articles, 10)  # 1ページあたり10件表示

    page_number = request.GET.get('page')  # 現在のページ番号を取得
    page_obj = paginator.get_page(page_number)

    return render(request, 'article_list.html', {'page_obj': page_obj})
  • Paginator(articles, 10): 記事を10件ずつのページに分割します。
  • get_page(page_number): リクエストから渡されたページ番号に対応するページオブジェクトを取得します。

テンプレートの作成

ページネーションを表示するテンプレートを作成します。

templates/article_list.html:

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>記事一覧</title>
</head>
<body>
    <h1>記事一覧</h1>

    <ul>
        {% for article in page_obj %}
        <li>
            <h2>{{ article.title }}</h2>
            <p>{{ article.content|truncatewords:20 }}</p>
            <p><small>公開日時: {{ article.published_at }}</small></p>
        </li>
        {% endfor %}
    </ul>

    <!-- ページネーションリンク -->
    <div>
        <span>現在のページ: {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</span>
        <div>
            {% if page_obj.has_previous %}
                <a href="?page=1">最初</a>
                <a href="?page={{ page_obj.previous_page_number }}">前へ</a>
            {% endif %}

            {% for num in page_obj.paginator.page_range %}
                {% if page_obj.number == num %}
                    <strong>{{ num }}</strong>
                {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
                    <a href="?page={{ num }}">{{ num }}</a>
                {% endif %}
            {% endfor %}

            {% if page_obj.has_next %}
                <a href="?page={{ page_obj.next_page_number }}">次へ</a>
                <a href="?page={{ page_obj.paginator.num_pages }}">最後</a>
            {% endif %}
        </div>
    </div>
</body>
</html>
  • page_obj.number: 現在のページ番号。
  • page_obj.paginator.num_pages: 全ページ数。
  • has_previousおよびhas_next: 前のページや次のページがあるかどうかをチェックします。

URLの設定

ビューを呼び出すためのURLパターンを設定します。

urls.py:

from django.urls import path
from .views import article_list_view

urlpatterns = [
    path('articles/', article_list_view, name='article_list'),
]

ページネーションのカスタマイズ

カスタムスタイルの適用

ページネーションリンクにBootstrapなどのCSSフレームワークを使ってスタイリングすることで、見た目を整えることができます。

例:Bootstrapを使ったスタイリング

<nav aria-label="Page navigation">
    <ul class="pagination">
        {% if page_obj.has_previous %}
            <li class="page-item">
                <a class="page-link" href="?page=1">&laquo; 最初</a>
            </li>
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.previous_page_number }}">&lsaquo; 前へ</a>
            </li>
        {% endif %}

        {% for num in page_obj.paginator.page_range %}
            {% if page_obj.number == num %}
                <li class="page-item active"><span class="page-link">{{ num }}</span></li>
            {% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
                <li class="page-item"><a class="page-link" href="?page={{ num }}">{{ num }}</a></li>
            {% endif %}
        {% endfor %}

        {% if page_obj.has_next %}
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.next_page_number }}">次へ &rsaquo;</a>
            </li>
            <li class="page-item">
                <a class="page-link" href="?page={{ page_obj.paginator.num_pages }}">最後 &raquo;</a>
            </li>
        {% endif %}
    </ul>
</nav>

まとめ

Djangoのページネーションは、標準機能を活用するだけで簡単に実装できます。ビューでのデータ取得からテンプレートでのリンク生成までの流れを理解すれば、大量のデータを扱うアプリケーションでも快適なユーザー体験を提供できます。