前回はCRUD操作のREADとBootstrapの導入を行いました。
今回は残りのCRUD操作を実装してToDoアプリを完成させます。
Create(新規作成)
Createを行う際は、CreateViewテンプレートを使用していきます。ListViewなどと使い方は一緒です。特徴はデータを新しく作成する時に適したテンプレートです。
ここからコードを実装しながら中身をみていきます。
まず、表示する画面を作成したいので、create.htmlファイルを作っていきましょう。
作成後は、todoディレクトリurls.pyを変更して繋ぎ込みを行っていきます。
./
├── db.sqlite3
├── manage.py
├── templates
│ ├── base.html
│ ├── create.html
│ ├── detail.html
│ └── list.html
├── todo
│ ├── init.py
│ ├── pycache
│ │ ├── init.cpython-37.pyc
│ │ ├── admin.cpython-37.pyc
│ │ ├── models.cpython-37.pyc
│ │ ├── urls.cpython-37.pyc
│ │ └── views.cpython-37.pyc
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20200418_1317.py
│ │ ├── init.py
│ │ └── pycache
│ │ ├── 0001_initial.cpython-37.pyc
│ │ ├── 0002_auto_20200418_1317.cpython-37.pyc
│ │ └── init.cpython-37.pyc
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
└── todoproject
├── init.py
├── pycache
│ ├── init.cpython-37.pyc
│ ├── settings.cpython-37.pyc
│ ├── urls.cpython-37.pyc
│ └── wsgi.cpython-37.pyc
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
from django.urls import path
from .views import TodoList, TodoDetail, TodoCreate
urlpatterns = [
path('list/', TodoList.as_view()),
path('detail/<int:pk>', TodoDetail.as_view()),
path('create/', TodoCreate.as_view()),
]
続いて、urls.pyに記載したTodoCreateクラスをviews.pyに実装していきます。
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView
from .models import TodoModel
from django.urls import reverse_lazy
class TodoList(ListView):
template_name = 'list.html'
model = TodoModel
class TodoDetail(DetailView):
template_name = 'detail.html'
model = TodoModel
class TodoCreate(CreateView):
template_name = 'create.html'
model = TodoModel
# 新規に書き込める項目を指定
fields = ('title', 'memo', 'priority', 'duedate')
# データ作成後のリダイレクト先を指定
success_url = reverse_lazy('list')
データ作成後にリダイレクト先に飛ばす方法として、reverse_lazyを使用しています。
ただ、今回はクラスで定義しているからreverse_lazyを使用して問題ないですが、関数で定義している場合は、reverseメソッドを使用してあげる必要があります。
これはdjangoの仕様なので、覚えるしかありません。
リダイレクト先の指定の仕方が少し独特で、urls.pyの内容を変更してreverse_lazyからurlを呼び出せるようにします。その為の変更が下記になります。
from django.urls import path
from .views import TodoList, TodoDetail, TodoCreate
urlpatterns = [
path('list/', TodoList.as_view(), name='list'),
path('detail/<int:pk>', TodoDetail.as_view(), name='detail'),
path('create/', TodoCreate.as_view(), name='create'),
]
これで、views.pyのreverse_lazy(‘list’)とリダイレクト先のurlが紐づきました。
そして、はじめに作成したcreate.htmlを作り込んでいきます。
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="作成する">
</form>
{% endblock content %}
{% csrf_token %}はdjangoで用意してくれているCSRF対策になります。
基本的にformを扱う際は必須なるので、つけ忘れないように注意してください。
{{ form.as_p }}はviews.pyで指定したDBのテーブルに書き込む項目を取得してpタグで自動的にhtml表示してくれます。
その他はHTMLの内容と一緒です。
ここまでできたら、サーバーを立ち上げて、データを入力してみましょう
データが入力されて、http://localhost:8000/list/ にリダイレクトされることが確認できるはずです。
Delete(削除)
CreateやReadの時と同様に、djangoがデータを削除するときに便利なテンプレートを用意しておいてくれています。
それが、DeleteViewです。
早速コードを実装していきます。
最初は、Createの時と同じで、delete.htmlを作成して、urls.pyと繋ぎ込みをします。
from django.urls import path
from .views import TodoList, TodoDetail, TodoCreate, TodoDelete
urlpatterns = [
path('list/', TodoList.as_view(), name='list'),
path('detail/<int:pk>', TodoDetail.as_view(), name='detail'),
path('create/', TodoCreate.as_view(), name='create'),
path('delete/<int:pk>', TodoDelete.as_view(), name='delete'),
]
次に、view.pyにdeleteのクラスを書いていきます。
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, DeleteView
from .models import TodoModel
from django.urls import reverse_lazy
class TodoList(ListView):
template_name = 'list.html'
model = TodoModel
class TodoDetail(DetailView):
template_name = 'detail.html'
model = TodoModel
class TodoCreate(CreateView):
template_name = 'create.html'
model = TodoModel
# 新規に書き込める項目を指定
fields = ('title', 'memo', 'priority', 'duedate')
# データ作成後のリダイレクト先を指定
success_url = reverse_lazy('list')
class TodoDelete(DeleteView):
template_name = 'delete.html'
model = TodoModel
success_url = reverse_lazy('list')
ここまでは似たような作業が続いてるので、慣れてきたと思います。
データを削除後も元の一覧画面に戻したいので、リダイレクト処理を書きます。
次にやることも予測がついてるかもしれませんが、delete.htmlを書き込んでいきます。
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">{% csrf_token %}
<input type="submit" value="削除します">
</form>
{% endblock content %}
ここまでできたら、サーバを立ち上げて、http://localhost:8000/delete/1 などにアクセスして、削除ボタンが表示されるか確認して、実行後削除されているか確認してください。
これで削除機能の実装が完了しました。
Update(更新)
Updateもほとんど同じなので、自分で実装できる方はやってみてください。
テンプレートはUpdateViewを使用します。
それでは、update.htmlの作成とurls.pyの変更からはじめます。
from django.urls import path
from .views import TodoList, TodoDetail, TodoCreate, TodoDelete, TodoUpdate
urlpatterns = [
path('list/', TodoList.as_view(), name='list'),
path('detail/<int:pk>', TodoDetail.as_view(), name='detail'),
path('create/', TodoCreate.as_view(), name='create'),
path('delete/<int:pk>', TodoDelete.as_view(), name='delete'),
path('update/<int:pk>', TodoUpdate.as_view(), name='update'),
]
続いて、views.pyの変更
from django.shortcuts import render
from django.views.generic import ListView, DetailView, CreateView, DeleteView, UpdateView
from .models import TodoModel
from django.urls import reverse_lazy
class TodoList(ListView):
template_name = 'list.html'
model = TodoModel
class TodoDetail(DetailView):
template_name = 'detail.html'
model = TodoModel
class TodoCreate(CreateView):
template_name = 'create.html'
model = TodoModel
# 新規に書き込める項目を指定
fields = ('title', 'memo', 'priority', 'duedate')
# データ作成後のリダイレクト先を指定
success_url = reverse_lazy('list')
class TodoDelete(DeleteView):
template_name = 'delete.html'
model = TodoModel
success_url = reverse_lazy('list')
class TodoUpdate(UpdateView):
template_name = 'update.html'
model = TodoModel
fields = ('title', 'memo', 'priority')
success_url = reverse_lazy('list')
update.htmlも基本的に一緒なのですが、唯一違うのフォームの中身にデータの内容を反映させてあげる程度です。
{% extends 'base.html' %}
{% block content %}
<form action="" method="POST">{% csrf_token %}
<div>{{ form.title }}</div>
<div>{{ form.memo }}</div>
<div>{{ form.priority }}</div>
<input type="submit" class="btn btn-primary" value="更新する">
</form>
{% endblock content %}
ここまでできたら、サーバーを立ち上げて確認してください。先程idが1のデータを削除してしまったので、http://localhost:8000/update/2 にアクセスしてフォームに出たの内容が反映されている点と、更新ができるかを確認します。
ここまででCRUDの全操作が完了しました。
最後に、今のままだとURLを直叩きしないと行けないので、編集のボタンなどにリンクを貼る作業をしていきます。
リンクの繋ぎ込み
list.htmlのボタンリンクを修正します。
{% extends 'base.html' %}
{% block header %}
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">ToDoリスト</h1>
<p class="lead">ToDoリストを管理することで生産性をアップしていきます。</p>
</div>
</div>
<h1></h1>
{% endblock header %}
{% block content %}
<div class='container'>
{% for item in object_list %}
<div class="alert alert-{{ item.priority }}" role="alert">
<p>{{ item.title }}<br> ー {{ item.memo }}</p>
<a class="btn btn-primary" href="{% url 'detail' item.pk %}" role="button">詳細</a>
<a class="btn btn-success" href="{% url 'update' item.pk %}" role="button">編集</a>
<a class="btn btn-danger" href="{% url 'delete' item.pk %}" role="button">削除</a>
</div>
{% endfor %}
</div>
{% endblock content %}
変更箇所は、href=”{% url ‘detail’ item.pk %}”の部分です。使い方はreverse_lazyと似ています。どのURLに飛ばすのかは、urls.pyで設定したnameの値を使います。更に、どのデータかを特定するために、DBに入ってるidを利用しています。
以上で、リンクの繋ぎ込みが完了しました。
おまけ
新規作成する為のボタンが抜けていたので、追記しました。
{% extends 'base.html' %}
{% block header %}
<div class="jumbotron jumbotron-fluid">
<div class="container">
<h1 class="display-4">ToDoリスト</h1>
<p class="lead">ToDoリストを管理することで生産性をアップしていきます。</p>
</div>
</div>
<h1></h1>
{% endblock header %}
{% block content %}
<div class='container'>
{% for item in object_list %}
<div class="alert alert-{{ item.priority }}" role="alert">
<p>{{ item.title }}<br> ー {{ item.memo }}</p>
<a class="btn btn-primary" href="{% url 'detail' item.pk %}" role="button">詳細</a>
<a class="btn btn-success" href="{% url 'update' item.pk %}" role="button">編集</a>
<a class="btn btn-danger" href="{% url 'delete' item.pk %}" role="button">削除</a>
</div>
{% endfor %}
<a class="btn btn-info" href="{% url 'create' %}" role="button">新規作成</a>
</div>
{% endblock content %}