Python Django 入門トップページ


Django によるコメント掲示板の開発:目次

  1. プロジェクトの作成
  2. Git でコミット
  3. Web サーバを起動しておく
  4. Config
  5. Comments アプリケーションを作る
  6. アプリケーションを有効にする
  7. はじめてのビューを作成する
  8. モデルを作る
  9. マイグレーション
  10. テストデータの設定
  11. データベースからコメント一覧を取得して表示してみよう
  12. Bootstrap の導入
  13. コメントの詳細表示
  14. urls.pyの書き方
  15. HTML のテンプレート化
  16. コメントの新規投稿
  17. コメントの編集機能を追加する
  18. さらにテンプレート化
  19. モデル,マイグレーションファイル,フォームの関連
  20. 入力内容の検証(バリデーション)
  21. コメントを削除する
  22. 一覧を逆順にする
  23. ページネーション
  24. フラッシュメッセージ
  25. Static コンテンツの設置
  26. 更新や削除にもフラッシュメッセージを表示
  27. テストの自動化を実現しよう
  28. デバッグツールバーを使う
  29. generic モジュールを使わずにコメント一覧を取得する
  30. コメント一覧のページネーション
  31. 一覧の表示順序を制御する
  32. generic モジュールを使わずにコメントの詳細を表示する
  33. コメント詳細にページ送り機能を作成する
  34. generic モジュールを使わずにコメント登録機能を作成する
  35. generic モジュールを使わずにコメント編集機能を作成する
  36. generic モジュールを使わずにコメント削除機能を作成する

Django によるコメント掲示板の開発

コメント詳細にページ送り機能を作成する

コメント一覧ページでは最終更新順にコメントが表示され,そのページからコメント詳細ページへリンクされている.ここでは,コメント詳細ページにおいて前のコメントや次のコメントの詳細ページい移動できるようなページ送り機能を作成してみよう.

ページ送り機能を作成するためには,詳細ページで表示したいコメントの情報を取得すると同時に,そのコメントの直前に更新されたものや直後に更新されたものを取得すれば良いことになります.よって,views.py の comments_show( ) 関数を次のように編集します.

comments/views.py
def comments_show(request, comment_id):
    context = {}
    comment = get_object_or_404(Comment, pk=comment_id)
    context['comment'] = comment

    # 1つ前(自身の直後に更新されたコメント)を取得する
    prev_comment = Comment.objects.filter(updated_at__gt=comment.updated_at).order_by('updated_at')
    # 1つ後(自身の直前に更新されたコメント)を取得する
    next_comment = Comment.objects.filter(updated_at__lt=comment.updated_at).order_by('-updated_at')
    if len(prev_comment) > 0:
        prev_id = prev_comment[0].id
    else:
        prev_id = False
    if len(next_comment) > 0:
        next_id = next_comment[0].id
    else:
        next_id = False
    context['prev_id'] = prev_id
    context['next_id'] = next_id

    return render(request, 'comments/show.html', context)

なお,上の7行目にある filter(updated_at__gt=comment.updated_at) は SQL の WHERE updated_at > comment.updated_at とほぼ同じような意味をもち,9行目にある filter(updated_at__lt=comment.updated_at) は SQL の WHERE updated_at < comment.updated_at のような意味になります.これ以外にも filter( ) による検索の書き方を表にまとめます.

書き方意味
項目名=値等しい
項目名__lt=値より小さい (Less Than)
項目名__lte=値以下 (Less Than or Equal to)
項目名__gt=値より大きい (Greater Than)
項目名__gte=値以上 (Greater Then or Equal to)

上のコードで context という辞書に,prev_idnext_id というキーで前後のコメント ID が格納されているはずなので,それらが正しく取得できているか show.html で表示してみます.次のように編集します.

comments/templates/comments/show.html(抜粋)
...(省略)
{% block content %}
    <div class="container">
        <h1 class="my-5">コメント {{ comment.id }}</h1>
        <p>前のコメントID: {{ prev_id }}</p>
        <p>次のコメントID: {{ next_id }}</p>
        <div class="card mb-3">
            <div class="card-header">
                ID : {{ comment.id }}
            </div>
            ...(省略)...

Webサーバを起動してブラウザで動作を確認します.最後から2番目に更新された id = 11, 最も更新が古い id = 2 の詳細ページを順に開きます.前後の ID が正しく取得できている(次や前がない場合は False になる)ことを確認してください.

(py39) C:\Users\lecture\Documents\django\django_comment>python manage.py runserver ⏎
Watching for file changes with StatReloader
Performing system checks...
django2022-00038
django2022-00039

次は,いま表示した前後のコメントIDをクリックしたらそのページが表示できるようにリンクを設定します.

comments/templates/comments/show.html(抜粋)
...(省略)...
{% block content %}
    <div class="container">
        <h1 class="my-5">コメント {{ comment.id }}</h1>
        <p>
            <a href="{% url 'comments:show' prev_id %}">
                前のコメントID: {{ prev_id }}
            </a>
        </p>
        <p>
            <a href="{% url 'comments:show' next_id %}">
                次のコメントID: {{ next_id }}
            </a>
        </p>
        <div class="card mb-3">
            <div class="card-header">
                ID : {{ comment.id }}
            </div>
・・・(省略)...

上のようなコードで概ね動作しますが,最新のページと最古のページでは直前または直後のコメントが存在しないのでエラーとなってしまいます.直前や直後のコメントが存在しない場合の処理なども必要になります.このような処理を記述しますが,せっかくなのでページネーションと同じようにレイアウト化しつつ,デザインも整えておきましょう.comments/templates/ フォルダに prev_next.html を作成します.

comments/templates/prev_next.html
<ul class="pagination justify-content-center pagination-lg g-mt-28 g-mb-28">
    {% if prev_id %}
        <li class="page-item">
            <a class="page-link" href="{% url 'comments:show' prev_id %}">
                <span aria-hidden="true">«</span>
            </a>
        </li>
    {% else %}
        <li class="page-item">
            <a class="page-link disabled">
                <span aria-hidden="true">«</span>
            </a>
        </li>
    {% endif %}
    {% if next_id %}
        <li class="page-item">
            <a class="page-link" href="{% url 'comments:show' next_id %}">
                <span aria-hidden="true">»</span>
            </a>
        </li>
    {% else %}
        <li class="page-item">
            <a class="page-link disabled">
                <span aria-hidden="true">»</span>
            </a>
        </li>
    {% endif %}
</ul>

show.html の中で今作成した prev_next.html を配置します.テンプレート化することで例えばページの上部と下部の2箇所に配置する事も簡単にできるようになります.同時に,詳細ページから一覧ページに戻るためのリンクも設置しておきます(配置・デザインの検討は必要でしょうが).

comments/templates/comments/show.html
{% extends "base.html" %}

{% block title %}
コメント {{ comment.id }}
{% endblock %}

{% block content %}
    <div class="container">
        <h1 class="my-5">コメント {{ comment.id }}</h1>
        {% include 'prev_next.html' %}
        <div class="card mb-3">
            <div class="card-header">
                ID : {{ comment.id }}
            </div>
            <div class="card-body">
                <p class="card-text">Title : </p>
                <h5 class="card-title">{{ comment.title }}</h5>
                <p class="card-text">Body : </p>
                <p class="card-text">{{ comment.body }}</p>
            </div>
            <div class="card-footer">
                Created at : {{ comment.created_at }}<br>
                Updated at : {{ comment.updated_at }}
            </div>
        </div>
        <hr>
        <div>
            <p>
                <a href="{% url 'comments:update' comment.id %}">
                    [ 編集 ]
                </a>
                <a href="{% url 'comments:delete' comment.id %}">
                    [ 削除 ]
                </a>
            </p>
            <p>
                <a href="{% url 'comments:index' %}">
                  一覧ページに戻る
                </a>
            </p>
        </div>
        {% include 'prev_next.html' %}
    </div>
{% endblock content %}

Webサーバを起動してブラウザで動作を確認します.

(py39) C:\Users\lecture\Documents\django\django_comment>python manage.py runserver ⏎
Watching for file changes with StatReloader
Performing system checks...
django2022-00040

目次に戻る