【Django】クラスベースビュー(class-based view):DetailViewを使用した詳細画面表示機能の実装

概要

クラスベースビュー(class-based view)で詳細画面表示機能を作成したのでまとめた。
詳細画面表示機能は、Djangoがもともと用意しているDetailViewクラスを継承して作成する。

DetailViewをどのように使用するのか、また処理イメージについて紹介する。

 

 

前提

以下の記事で作成した一覧画面表示機能に関連する機能になる。

あわせて読みたい

概要 クラスベースビュー(class-based view)で一覧検索機能を作成したのでまとめた。 一覧検索機能は、Djangoがもともと用意しているListViewクラスを継承してを作成する。   前提 Djang[…]

【Django】クラスベースビューListViewを使用した一覧取得機能

 

 

画面遷移

今回実装する詳細画面表示機能の画面イメージは以下となる。

【Django】クラスベースビュー(class-based view):DetailViewを使用した詳細画面表示機能の実装_一覧画面表示
▲タスク名に詳細画面表示用のリンクを追加

 

【Django】クラスベースビュー(class-based view):DetailViewを使用した詳細画面表示機能の実装_詳細画面表示
▲一覧画面のタスク名リンクを押下すると、対象の情報をTODOテーブルから取得して表示する

 

 

詳細画面表示機能の実装

サーバー側

ルーティング

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をどのように[…]

【Django】クラスベースビュー(class-based view):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>

 

{% url ‘リクエスト先のビューの名前クエリパラメータ %}

上記のルールで記述することで、画面からクエリパラメータを送信できる。
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テンプレートの使い方について、当アプリを作成しながら[…]

【Flask】TODOアプリ作成その4:タスク詳細、編集、削除機能の実装

 

【Django】クラスベースビュー(class-based view):DetailViewを使用した詳細画面表示機能の実装_改行コード確認
▲改行を入力すると、改行コード(\r\n)に変換されてテーブル登録される

 

【Django】クラスベースビュー(class-based view):DetailViewを使用した詳細画面表示機能の実装_改行コードエスケープ
▲改行コードがエスケープされると、上記のように改行されずに表示される

以上が詳細画面表示処理になる。

 

その他

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メモ'

 

 

 

 

 

スポンサーリンク