コメント一覧ページでは最終更新順にコメントが表示され,そのページからコメント詳細ページへリンクされている.ここでは,コメント詳細ページにおいて前のコメントや次のコメントの詳細ページい移動できるようなページ送り機能を作成してみよう.
ページ送り機能を作成するためには,詳細ページで表示したいコメントの情報を取得すると同時に,そのコメントの直前に更新されたものや直後に更新されたものを取得すれば良いことになります.よって,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_id
や next_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サーバを起動してブラウザで動作を確認します.最も最後に更新された id = 9, その次の id = 10,最も更新が古い id = 1 の詳細ページを順に開きます.前後の ID が正しく取得できていることを確認してください.
python manage.py runserver ⏎
次は,いま表示した前後のコメント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 class="pull-right">
<a href="{% url 'comments:index' %}">
一覧ページに戻る
</a>
</p>
</div>
{% include 'prev_next.html' %}
</div>
{% endblock content %}
Webサーバを起動してブラウザで動作を確認します.
python manage.py runserver ⏎