Python Django入門 初めの1歩からWEBアプリ作成までの流れ その16 CreateView, ListView, DetailView, UpdateView, DeleteViewを使ったタスク管理アプリの作成

みなさんこんにちは、ZeroTerasu(@ZeroTerasu)です。

今回は、以前に解説した「CreateView, ListView, DetailView, UpdateView, DeleteView」の5つの主要なテンプレートビューを使ったアプリを作っていきたいと思います。

尚、今回は下記の設定で進めていきます。

プロジェクト名とアプリ名

プロジェクト名=”pj”

アプリ名=”tasks”

今回の内容はこちらです。

今回の内容
ポイント①:models.pyにTaskモデルを作成。
ポイント②:views.pyにCreateView, ListView, DetailView, UpdateView, DeleteViewを継承したビューを作成。
ポイント③:urls.pyでビューとテンプレートを紐付け。
ポイント④:テンプレートの作成

アプリの概要説明

アプリの内容

下記の3ステップのような流れでユーザー登録機能を実装していきます。

トップページ

・トップページには登録ページへのリンク先を設定します。

登録ページ

・forms.pyでSignUpForm内に設定したフィールドが表示されるようになっています。

ログイン成功ページ

・ユーザー登録が無事に完了した後、ユーザー名が表示されるようにしています。

ポイント①:models.pyにTaskモデルを作成。

models.py
from django.db import models

class Task(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField()
    completed = models.BooleanField(default=False)

    def __str__(self):
        return self.title
コード解説

 このコードにより、Taskという名前のモデルが作成され、titledescriptioncompletedというフィールドが追加されます。このモデルを使用すると、タスクのタイトル説明、および完了状態をデータベースに保存することができます。

ポイント②:views.pyにCreateView, ListView, DetailView, UpdateView, DeleteViewを継承したビューを作成。

views.py
from django.views.generic import CreateView, ListView, DetailView, UpdateView, DeleteView
from django.urls import reverse_lazy
from .models import Task

class TaskCreateView(CreateView):
    model = Task
    template_name = 'tasks/task_form.html'
    fields = ['title', 'description']
    success_url = reverse_lazy('task-list')

class TaskListView(ListView):
    model = Task
    template_name = 'tasks/task_list.html'
    context_object_name = 'tasks'

class TaskDetailView(DetailView):
    model = Task
    template_name = 'tasks/task_detail.html'
    context_object_name = 'task'

class TaskUpdateView(UpdateView):
    model = Task
    template_name = 'tasks/task_form.html'
    fields = ['title', 'description']
    success_url = reverse_lazy('task-list')

class TaskDeleteView(DeleteView):
    model = Task
    template_name = 'tasks/task_confirm_delete.html'
    success_url = reverse_lazy('task-list')

context_object_name解説

context_object_name解説

 context_object_nameは、Djangoのクラスベースビュー(Class-Based View)で使用される属性の1つです。この属性を使用すると、ビューからテンプレートにモデルの各属性を渡すことができます。context_object_nameに指定したコンテキスト変数名をテンプレート内でテンプレートタグに渡すことで、テンプレートでモデルのデータを受け取ることが出来るようになります。

 使い方の例を示します。以下のようなクラスベースビューがあるとします。

from django.views.generic import DetailView
from .models import Task

class TaskDetailView(DetailView):
    model = Task
    context_object_name = 'task'
    template_name = 'task_detail.html'

 上記のコードでは、TaskDetailViewがTaskモデルの詳細ビューを表しています。context_object_name属性は、ビューテンプレートでタスクオブジェクトを参照するためのコンテキスト変数の名前を指定しています。

 template_name属性は、使用するテンプレートの名前を指定します。

 task_detail.htmlテンプレート内で、context_object_nameで指定した名前の変数(task)を使用してオブジェクトにアクセスできます。例えば、次のようになります。

<h1>{{ task.title }}</h1>
<p>{{ task.description }}</p>

 上記のコードでは、task_detail.htmlテンプレートでtask変数を使用してタスクオブジェクトの属性にアクセスしています。

 context_object_nameを使用することで、ビューテンプレートでオブジェクトを参照するための変数名を自由に設定することができます。

テンプレートビュー別設定属性

テンプレートビュー別設定属性
属性1 属性2 属性3 属性4
CreateView model template_name fields success_url
ListView model template_name context_object_name
DetailView model template_name context_object_name
UpdateView model template_name fields success_url
DeleteView model template_name success_url

ポイント③:urls.pyでビューとテンプレートを紐付け。

pj/tasks/urls.py
from django.urls import path
from .views import (
    TaskCreateView,
    TaskListView,
    TaskDetailView,
    TaskUpdateView,
    TaskDeleteView,
)

urlpatterns = [
    path('task/create/', TaskCreateView.as_view(), name='task-create'),
    path('task/list/', TaskListView.as_view(), name='task-list'),
    path('task/detail/<int:pk>/', TaskDetailView.as_view(), name='task-detail'),
    path('task/update/<int:pk>/', TaskUpdateView.as_view(), name='task-update'),
    path('task/delete/<int:pk>/', TaskDeleteView.as_view(), name='task-delete'),
]
ListViewとDetailViewの違い

テーブルで見るListViewとDetailViewの参照先の違い

ListView:モデル属性に指定したモデルのテーブル全体を表示するビューです。

DetailView:モデル属性に指定したモデルのテーブルの特定の1行を表示するビューです。URLの<int:pk>から上記のテーブル内のIDを取得します。

<int:pk>の意味

 <int:pk>はDjangoのURLパターンで使用される特殊な構文です。<int:pk>は整数値を表すパラメータ(プライマリキー)URLの一部として受け取ることを示します。

 具体的には、<int:pk>はURLの一部であり、整数の値がpkという名前の変数に割り当てられます。このパラメータは、ビューに渡されてオブジェクトを一意に特定するために使用されることが一般的です。

 例えば、以下のようなURLがあるとします。

/task/detail/1/

このURLでは、パラメータに1という整数値が渡されます。pk変数には1が割り当てられます。

ビューでこのパラメータを利用する場合、例えばTaskDetailViewでは、渡されたpkの値を使用して特定のタスクオブジェクトを取得できます。以下はビューの例です。

from django.views.generic import DetailView
from .models import Task

class TaskDetailView(DetailView):
    model = Task
    context_object_name = 'task'
    template_name = 'task_detail.html'

このビューでは、pkパラメータの値を使用して特定のタスクオブジェクトをデータベースから取得し、テンプレートに渡します。ビュー内でself.kwargs[‘pk’]を使用することで、pkの値にアクセスできます。

パターンは、一般的にDjangoのDetailViewUpdateViewなどのビュークラスで使用され、データベースの特定のオブジェクトを取得するためのパラメータとして利用されます

 self.kwargs[‘pk’]は、Djangoのクラスベースビュー内で使用される特殊な属性です。これは、ビューのキーワード引数(kwargs)に含まれるパラメータ(pk)の値にアクセスするために使用されます。

 self.kwargsは、ビューのキーワード引数を格納する辞書です。ビューに渡されたすべてのキーワード引数は、この辞書に格納されます。

 self.kwargs[‘pk’]は、kwargs辞書からキーがpkの値を取得するための記法です。この場合、pkはパターンによって渡された整数値のプライマリキーを指します。

たとえば、以下のようなURLがあるとします。

/task/detail/1/

 このURLでpkパラメータに渡された値は1です。ビュー内のself.kwargs[‘pk’]を使用することで、1にアクセスできます。

 DetailViewやUpdateViewなどのビューでは、pkパラメータを使用してデータベースから特定のオブジェクトを取得したり、その他の処理で使用したりすることがよくあります。ビューの内部でself.kwargs[‘pk’]を使用することで、渡されたpkの値を利用できます。

ポイント④:テンプレートの作成

pj/templates/registration/base.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{% block title %}タイトル{% endblock %}</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</head>
<body>
{% block main %}
{% endblock %}
</body>
</html>
コード解説

①<link>タグのリンク:

href=”https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css”: BootstrapのCSSスタイルシートファイルへのリンクです。このスタイルシートは、ウェブページのスタイルを定義し、Bootstrapのコンポーネントやレイアウトを適用します。

②<script>タグのスクリプト

・src=”https://code.jquery.com/jquery-3.2.1.slim.min.js”: jQueryライブラリへのリンクです。jQueryはJavaScriptのライブラリであり、DOM操作やイベント処理などを簡略化するための便利な機能を提供します。

・src=”https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js”: Popper.jsへのリンクです。Popper.jsは、ツールチップやポップオーバーなどのポップアップコンポーネントを制御するためのライブラリです。

・src=”https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js”: BootstrapのJavaScriptファイルへのリンクです。このファイルには、BootstrapのコンポーネントやJavaScriptに関連する機能が含まれています。

pj/templates/registration/task_create.html(CreateViewのテンプレート)
{% extends 'tasks/base.html' %}
{% block title %}タスク作成画面{% endblock %}
{% block main %}
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
    <a href="/" class="navbar-brand">タスク作成画面</a>
</nav>
<div class="container mt-4">
<form method="POST">
    {% csrf_token %}
    <div>
      <label for="id_title">タイトル:</label>
      {{ form.title }}
    </div>
    <div>
      <label for="id_description">説明:</label>
      {{ form.description }}
    </div>
    <button type="submit" class="btn btn-primary btn-lg">保存</button>
  </form> 
</div>
{% endblock %}
コード解説

 このテンプレートでは、formオブジェクトの各フィールドを表示しています。{% csrf_token %}は、Djangoのセキュリティ保護機能であるCSRFトークンを挿入するためのテンプレートタグです。フォームの各フィールドは、{{ form.field_name }}の形式で表示されます。

 label要素を使用してフィールドのラベルを表示し、form.field_nameでフィールドを表示します。

 このテンプレートをtask_create.htmlとして保存し、CreateViewに関連付けることで、新しいタスクの作成フォームを表示することができます。

 id_titleは、Taskモデルのtitleフィールドに関連付けられたHTML要素のid属性です。このid属性は、フォームフィールドとラベルを関連付けるために使用されます。

 通常、Djangoのフォームフィールドは、自動的にid属性を生成します。id属性は、JavaScriptやCSSなどのクライアントサイドの処理でフォームフィールドを識別するために使用されます。

pj/templates/registration/task_form.html(UpdateViewのテンプレート)
<form method="POST">
  {% csrf_token %}
  <div>
    <label for="id_title">タイトル:</label>
    {{ form.title }}
  </div>
  <div>
    <label for="id_description">説明:</label>
    {{ form.description }}
  </div>
  <div>
    <label for="id_completed">完了:</label>
    {{ form.completed }}
  </div>
  <button type="submit">保存</button>
</form>

または、下記でも代用可能です。

<form method="POST">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit">保存</button>
</form>
コード解説

task_create.htmlの解説と同じです。

ListViewのテンプレート

pj/templates/registration/task_list.html(ListView用のテンプレート)
{% for task in tasks %}
  <div>
    <h2>{{ task.title }}</h2>
    <p>{{ task.description }}</p>
    <p>{% if task.completed %}完了{% else %}未完了{% endif %}</p>
    <a href="{% url 'task-detail' task.pk %}">詳細</a>
    <a href="{% url 'task-update' task.pk %}">編集</a>
    <a href="{% url 'task-delete' task.pk %}">削除</a>
  </div>
{% empty %}
  <p>タスクがありません。</p>
{% endfor %}
コード解説

①モデルの全テーブルを取得:{% for 任意の要素名 in context_object_nameの属性値 %}

ListViewとDetailViewの違いについての解説箇所の通り、ListViewに紐づけられたテンプレート内では、ListViewのcontext_object_name属性値{% for 任意の要素名 in context_object_nameの属性値 %}のように指定することで、ListViewに紐づけられたモデルの全テーブルを取得することが出来ます。

②モデルの全テーブルから1行ずつデータを抽出:{{ ①で使った任意の要素名.モデルの属性 }}

通常、ListViewに紐づけられたテンプレート内では、①のテンプレートタグ{% for %}を使ってモデルの全テーブルから1行ずつデータを抽出してきます。抽出された各行のデータは、変数タグ{{ ①で使った任意の要素名.モデルの属性 }}を使って抽出することでデータを表示します。

③各行のデータの詳細・編集・削除のリンクを設定:{% url ‘urls.pyで設定したルート‘ context_object_name属性値.pk %}

③モデルの各行のデータの詳細・編集・削除のリンクを下記の{%url%}タグを使って設定する。
{% url ‘urls.pyで設定したルートcontext_object_name属性値.pk %}

DetailViewのテンプレート

pj/templates/registration/task_detail.html(DetailView用のテンプレート)
<h2>{{ task.title }}</h2>
<p>{{ task.description }}</p>
<p>{% if task.completed %}完了{% else %}未完了{% endif %}</p>
<a href="{% url 'task-update' task.pk %}">編集</a>
<a href="{% url 'task-delete' task.pk %}">削除</a>
コード解説

①DetailViewで紐づけたモデルからpkのIDを持つデータを取得:{{ context_object_nameの属性値.モデルの属性 }}

ListViewとDetailViewの違いについての解説箇所の通り、DetailViewに紐づけられたテンプレート内では、DetailViewのcontext_object_name属性値{{ context_object_nameの属性値.モデルの属性 }}のように変数タグ{{}}を使って指定することで、DetailViewに紐づけられたモデルの中のアクセスしたURLの末尾の数字(pk)IDを持つ1つの行のデータを取得することが出来ます。

②データの詳細・編集・削除のリンクを設定:{% url ‘urls.pyで設定したルート‘ context_object_name属性値.pk %}

③データの詳細・編集・削除のリンクを下記の{%url%}タグを使って設定する。
{% url ‘urls.pyで設定したルートcontext_object_name属性値.pk %}

pj/templates/registration/task_confirm_delete.html(DeleteView用のテンプレート)
<h2>タスクを削除しますか?</h2>
<p>{{ task.title }}</p>
<form method="POST">
  {% csrf_token %}
  <button type="submit">削除</button>
  <a href="{% url 'task-detail' task.pk %}">キャンセル</a>
</form>
コード解説

特になし。

コメント

タイトルとURLをコピーしました