概要
クラスベースビュー(class-based view)で詳細画面表示機能を作成したのでまとめた。
詳細画面表示機能は、Djangoがもともと用意しているDetailViewクラスを継承して作成する。
DetailViewをどのように使用するのか、また処理イメージについて紹介する。
前提
以下の記事で作成した一覧画面表示機能に関連する機能になる。
概要 クラスベースビュー(class-based view)で一覧検索機能を作成したのでまとめた。 一覧検索機能は、Djangoがもともと用意しているListViewクラスを継承してを作成する。 前提 Djang[…]
画面遷移
今回実装する詳細画面表示機能の画面イメージは以下となる。
詳細画面表示機能の実装
サーバー側
ルーティング
todoapps/urls.py
from django.urls import path
from . import views
urlpatterns = [
path("tasks/", views.TodoTopView.as_view(), name="top"),
path("detail/<int:pk>/", views.TodoDetailView.as_view(), name="detail"),
]
上記により、サーバーを起動して「http://localhost:8000/detail/XX/」にアクセスすると、viewsファイルに定義している詳細画面表示ビュー(TodoDetailViewクラス)の処理を呼ぶ。
詳細画面表示ビュー
todoapps/views.py
from django.views.generic import ListView, DetailView
from . import models
from django.contrib.auth.mixins import LoginRequiredMixin
class TodoTopView(LoginRequiredMixin, ListView):
"""TODOリスト一覧表示"""
model = models.Todo
template_name = "todo/top.html"
context_object_name = "tasks"
def get_queryset(self):
return models.Todo.objects.filter(status=0).order_by("due_date")
class TodoDetailView(LoginRequiredMixin, DetailView):
"""TODO詳細画面表示"""
model = models.Todo
context_object_name = "todo"
template_name = "todo/detail.html"
class TodoDetailView(LoginRequiredMixin, DetailView):
詳細画面の表示処理を作成するには、クラスベースビューのDetailViewを継承して作成する。
また、LoginRequiredMixinはログインした状態じゃないとURLリクエストできないようにアクセス制御をつけるため実装している。
LoginRequiredMixinについては以下のアクセス制御を参照。
概要 クラスベースビュー(class-based view)で会員登録機能を作成したのでまとめた。 会員登録機能は、Djangoがもともと用意しているCreateViewクラスを継承して作成する。 CreateViewをどのように[…]
model = models.Todo
modelには検索レコードを取得するための、対象のテーブルオブジェクトを設定する。
画面から送られたクエリパラメータを条件に、上記テーブルからレコードを取得する。
尚、データを検索&取得してコンテキストに設定するところまでDetailViewが自動で行うため、処理の動きがブラックボックスとなる。
context_object_name = "todo"
デフォルトではコンテキスト名(画面に渡す辞書データ)は「object」となる。
画面側で「object」というコンテキストを取得するのは抽象的な名前すぎるので、「todo」としている。
template_name = "todo/detail.html"
template_nameには、詳細画面のテンプレート(HTML)パスを設定する。
画面側
一覧表示画面
タスク詳細を表示するリクエストを送るため、リンクを追加する。
templates/todo/detail.html
<tbody>
{% for todo in tasks %}
<tr>
<td>{{ todo.category }}</td>
<td><a href="{% url 'detail' todo.pk %}">{{ todo.task }}</td>
<td>{{ todo.due_date|date:"Y年m月d日" }}</td>
<td>
{% if todo.status == 0 %}
未完了
{% else %}
完了
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
上記のルールで記述することで、画面からクエリパラメータを送信できる。
urls.py側でパラメータの名称は合わせること。
詳細画面表示
templates/todo/detail.html
{% extends "base.html" %}
{% block title %}TODO詳細{% endblock %}
{% block main %}
<div class="container mt-2">
<a href="{% url 'top' %}" class="btn btn-primary mb-3">戻る</a>
<h2 class="text-center">TODO詳細</h2>
<div class="card mt-4 border">
<div class="card-body">
<div class="row border p-2 mb-2">
<div class="col-sm-3">
<h5>カテゴリ:</h5>
</div>
<div class="col-sm-9">
<p>{{ todo.category }}</p>
</div>
</div>
<div class="row border p-2 mb-2">
<div class="col-sm-3">
<h5>タスク:</h5>
</div>
<div class="col-sm-9">
<p>{{ todo.task }}</p>
</div>
</div>
<div class="row border p-2 mb-2">
<div class="col-sm-3">
<h5>ステータス:</h5>
</div>
<div class="col-sm-9">
<p>
{% if todo.status == 0 %}
未完了
{% else %}
完了
{% endif %}
</p>
</div>
</div>
<div class="row border p-2 mb-2">
<div class="col-sm-3">
<h5>メモ:</h5>
</div>
<div class="col-sm-9">
{% if todo.memo %}
<p>{{ todo.memo|linebreaksbr|safe }}</p>
{% endif %}
</div>
</div>
<div class="row border p-2 mb-2">
<div class="col-sm-3">
<h5>期日:</h5>
</div>
<div class="col-sm-9">
<p>{{ todo.due_date }}</p>
</div>
</div>
<div class="d-flex justify-content-center mt-2">
</div>
</div>
</div>
</div>
{% endblock %}
基本的に詳細画面ではサーバーから送られてきたコンテキスト「todo」を画面表示しているだけ。
{% if todo.memo %}
<p>{{ todo.memo|linebreaksbr|safe }}</p>
{% endif %}
メモの入力フィールドはテキストエリアのため、改行入力が可能になる。
改行が入力されると、改行コードがテーブルに保存される。
改行コードは画面に表示しようとすると、Djangoのテンプレート側でエスケープしてしまうため、うまく表示できない。
「linebreaksbr」フィルタと「safe」フィルタを記述すれば、改行コードをエスケープしないように記述できる模様。
尚、以下の記事ではJinjaテンプレートの改行コードに関する対応を記述しているが、Djangoのテンプレートでは同じ記述ができなかった。
概要 Pythonのflaskフレームワークを使用して、TODOリストを管理するWEBアプリを作成したのでまとめた。 flaskのGET/POSTの方法やセッション等の扱い、Jinjaテンプレートの使い方について、当アプリを作成しながら[…]
以上が詳細画面表示処理になる。
その他
DetailViewのコンテキストを確認したいとき
クラスベースビューの処理はブラックボックスすぎて、どんな値を画面に返却しているのかわかりづらい。
そんなとき、get_context_dataをオーバーライド(上書き)すれば、画面に渡すコンテキスト(辞書データ)の中身を確認できる。
get_context_dataをオーバーライド
todoapps/views.py
class TodoDetailView(LoginRequiredMixin, DetailView):
""" TODO詳細画面表示 """
model = models.Todo
context_object_name = "todo"
template_name = "todo/detail.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
print(context)
print(repr(context["todo"].memo))
return context
親クラスのget_context_dataメソッドのcontextが、画面に渡しているcontextの中身になる。
context_object_name属性に設定した内容も反映されたデータとなる。
上記のように記述して、contextをprintすればターミナルにログが出力されるので確認できる。
ターミナル
{'object': <Todo: ●●店にて打合せ>, 'todo': <Todo: ●●店にて打合せ>, 'view': <todoapps.views.TodoDetailView object at 0x7fdf8c0b3580>}
'打合せ\r\nメモ'