今回は、登録済みデータの更新、削除機能を実装していきます。
データの修正機能を作成する
データの更新機能で使うテンプレートファイルは、新規作成のときと同じinquiry_form.htmlを利用することができます。
更新用のview関数の中で、登録済みのデータをテンプレートに渡してあげればOKです。
views.py
def inquiry_update(request, pk):
inquiry = Inquiry.objects.get(id=pk)
form = InquiryModelForm(instance=inquiry)
if request.method == 'POST':
form = InquiryModelForm(request.POST, instance=inquiry)
if form.is_valid():
form.save()
return redirect('DjangoApp:inquiry-list')
context = {
'form': form,
}
return render(request, 'DjangoApp/inquiry_form.html', context)
更新対象のデータを取得して、フォームのインスタンスとして指定しています。
こうすることで、新規作成と同じフォームを利用しながら、登録済みのデータを初期値として
各フィールドにセットすることができます。
更新の保存処理自体は、新規作成の処理と同じです。
Djangoでは、同じsave()メソッドで新規作成・更新を行うことができます。
プライマリキー属性がセットされている(Noneや空文字列等でない場合)には、Updateが実行されます。そうでない場合、または、Update実行操作によりいずれのデータも更新されなかった場合には、Insert処理が実行されます。
URL情報を追加します。
DjangoApp/urls.py
from django.urls import path
from .views import dashboard, inquiry_create, inquiry_list, inquiry_detail, inquiry_update
app_name = 'DjangoApp'
urlpatterns = [
path('', dashboard, name='dashboard'),
path('create/', inquiry_create, name='inquiry-create'),
path('list/', inquiry_list, name='inquiry-list'),
path('<int:pk>/', inquiry_detail, name='inquiry-detail'),
path('update/<int:pk>/', inquiry_update, name='inquiry-update'),
]
更新するレコードを特定しないといけないので、<int:pk>を入れています。
では、試してみましょう。
入力フォームにはじめから値がセットされていますね。
適当に値を変えて、送信ボタンを押してみてください。
詳細ページで確認すると、値が更新されているのがわかります。
詳細表示ボタン、更新ボタン、削除ボタンを追加する
削除機能を追加する前に、少しテンプレートに手を加えます。
これまで、各ページへ飛ぶのにURLを直打ちしてきましたが、実際にはボタン等でページを移動します。
まず、ページ上部のメニューにリンク先を設定します。
Inquiryメニューをクリックしたときには、受付機能のトップページ(inquiry-dashboard)を表示できるようにします。
inquiry_dashboard.html
{% extends 'DjangoApp/base.html' %}
{% block content %}
<div class="row col-md-12">
<div class="col col-md-2">
{% include 'DjangoApp/inquiry_menu.html' %}
</div>
<div class="col col-md-10">
<h1>コンテンツの中身</h1>
</div>
</div>
{% endblock %}
DjangoApp/urls.py
from django.urls import path
from .views import (
dashboard,
inquiry_dashboard,
inquiry_create,
inquiry_list,
inquiry_detail,
inquiry_update)
app_name = 'DjangoApp'
urlpatterns = [
path('', dashboard, name='dashboard'),
path('dashboard/', inquiry_dashboard, name='inquiry-dashboard'),
path('create/', inquiry_create, name='inquiry-create'),
path('list/', inquiry_list, name='inquiry-list'),
path('<int:pk>/', inquiry_detail, name='inquiry-detail'),
path('update/<int:pk>/', inquiry_update, name='inquiry-update'),
]
トップページ用のview関数を定義します。
views.py
def inquiry_dashboard(request):
return render(request, 'DjangoApp/inquiry_dashboard.html', {})
ヘッダーのリンク情報を修正します。
header.html
{% load static %}
<nav class="navbar navbar-expand-md navbar-dark bg-dark justify-content-between"">
<img src=" {% static 'DjangoApp/img/logo.png' %}" alt="logo">
<ul class="navbar-nav">
<li class="nav-item"><a href="{% url 'DjangoApp:dashboard' %}" class="nav-link">Dashboad</a></li>
<li class="nav-item"><a href="{% url 'DjangoApp:inquiry-dashboard' %}" class="nav-link">Inquiry</a></li>
<li class="nav-item"><a href="" class="nav-link">About</a></li>
</ul>
</nav>
リンク先を表すhref属性は、以下の形式で指定しています。
{% url 'リンク先' パラメータ %}
リンク先には、views.urls.pyで定義したnameを入力します。
この部分では、パラメータは不要ですが、レコードのプライマリーキー情報を指定する必要がある場合など(<int:pk>の情報)、パラメータの部分に各レコードのidを入力してしたります。
次にナビゲーションメニューのメニュー2に「受付一覧」へのリンク情報を追加します。
ダッシュボードメニューにもリンク先を指定しておきます。
また、Inquiryメニューを押したときは、ダッシュボードを開くようにしておきます。
inquiry_menu.html
<nav class="navbar">
<ul class="navbar-nav">
<li class="nav-item"><a href="{% url 'DjangoApp:inquiry-dashboard' %}" class="nav-link">ダッシュボード</a></li>
<li class="nav-item"><a href="{% url 'DjangoApp:inquiry-link' %}" class="nav-link">受付一覧</a></li>
<li class="nav-item"><a href="" class="nav-link">メニュー3</a></li>
</ul>
</nav>
次に、一覧ページを修正します。
inquiry_list.html
{% extends 'DjangoApp/base.html' %}
{% block content %}
<div class="row">
<div class="col col-md-2">
{% include 'DjangoApp/inquiry_menu.html' %}
</div>
<div class="col col-md-10">
<div class="row my-2 border-bottom bor-der-primary">
<h2 class="pl-2">受付一覧</h2>
</div>
<table class="table table-dm">
<tr>
<th></th>
<th>緊急度</th>
<th>ステータス</th>
<th>件名</th>
<th>顧客名</th>
<th>受付日時</th>
</tr>
{% for item in inquirys %}
<tr>
<td>
<a href="{% url 'DjangoApp:inquiry-detail' item.id %}" class="btn btn-info">表示</a>
<a href="{% url 'DjangoApp:inquiry-update' item.id %}" class="btn btn-primary">更新</a>
<a href="" class="btn btn-warning">削除</a>
</td>
<td>{{ item.get_emergency_display }}</td>
<td>{{ item.get_status_display }}</td>
<td>{{ item.subject }}</td>
<td>{{ item.customer }}</td>
<td>{{ item.reception_datetime }}</td>
</tr>
{% endfor %}
</table>
</div>
</div>
{% endblock %}
一覧テーブルで空にしておいた<td>タグのところに「表示」、「更新」、「削除」リンクを追加しました。クラスによって、ボタン風に表示させます。
削除機能は未定義ですのでとりあえず、空にしてあります。
表示ボタンや更新ボタンを押してみてください。それぞれの表示に正しく切り替わりますよね。
また、詳細表示ページからも更新や削除へ飛べたらいいですよね。追加します。
inquiry_detail.html
{% extends 'DjangoApp/base.html' %}
{% load verbose_name %}
{% block content %}
<div class="row">
<div class="col col-md-2">
{% include 'DjangoApp/inquiry_menu.html' %}
</div>
<div class="col col-md-10">
<div class="row my-2 border-bottom bor-der-primary">
<h2 class="pl-2">受付入力</h2>
</div>
<div class="row pl-2">
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'emergency' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.get_emergency_display }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'status' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.get_status_display }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'subject' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.subject }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'customer' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.customer }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'category' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.category }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'reception_datetime' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.reception_datetime }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'content' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.content }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'request' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.request }}</p>
</div>
</div>
<div class="row col-pl2">
<div class="row col-md-12">
<a href="{% url 'DjangoApp:inquiry-update' inquiry.id %}" class="btn btn-primary">更新</a>
<a href="" class="offset-md-10 btn btn-warning">削除</a>
</div>
</div>
</div>
</div>
{% endblock %}
とりあえず、ページ遷移の処理はこれくらいでしょうか。
削除機能を作成する。
削除ページは、データの詳細ページに削除確認メッセージを追加する形で行きましょう。
inquiry_delete.html
{% extends 'DjangoApp/base.html' %}
{% load verbose_name %}
{% block content %}
<div class="row">
<div class="col col-md-2">
{% include 'DjangoApp/inquiry_menu.html' %}
</div>
<div class="col col-md-10">
<div class="row my-2 border-bottom bor-der-primary">
<h2 class="pl-2">受付削除</h2>
</div>
<div class="row pl-2">
<label for="" class="text-danger">本当にこのレコードを削除してもよろしいですか?</label>
</div>
<div class="row pl-2">
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'emergency' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.get_emergency_display }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'status' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.get_status_display }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'subject' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.subject }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'customer' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.customer }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'category' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.category }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'reception_datetime' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.reception_datetime }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'content' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.content }}</p>
</div>
<div class="row col-md-12">
<p class="col col-md-2">{% get_verbose_field_name inquiry 'request' %}</p>
<p class="col col-md-10 text-primary">{{ inquiry.request }}</p>
</div>
</div>
<div class="row pl-2">
<div class="row col-md-12">
<div class="col">
<form action="{% url 'DjangoApp:inquiry-delete' inquiry.id %}" class="form-group" method="POST">
{% csrf_token %}
<a href="{{ request.META.HTTP_REFERER }}">戻る</a>
<input type="submit" name="submit" value='削除' class="offset-md-10 btn-danger">
</form>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
POSTされたときに、対象レコードを特定するためにacrion属性には対象のレコードidを付与したURLを指定しています。
この情報をもとにPOSTされたときにレコードの削除を実行します。
views.py
ef inquiry_delete(request, pk):
inquiry = Inquiry.objects.get(id=pk)
if request.method == 'POST':
inquiry.delete()
return redirect('DjangoApp:inquiry-list')
context = {
'inquiry': inquiry,
}
return render(request, 'DjangoApp/inquiry_delete.html', context)
POSTされたときには、対象のオブジェクトのdeleteメソッドを呼んであげるだけでOKです。
完了後は、一覧ページに遷移するようにします。
DjangoApp/urls.py
from django.urls import path
from .views import (
dashboard,
inquiry_dashboard,
inquiry_create,
inquiry_list,
inquiry_detail,
inquiry_update,
inquiry_delete, )
app_name = 'DjangoApp'
urlpatterns = [
path('', dashboard, name='dashboard'),
path('dashboard/', inquiry_dashboard, name='inquiry-dashboard'),
path('create/', inquiry_create, name='inquiry-create'),
path('list/', inquiry_list, name='inquiry-list'),
path('<int:pk>/', inquiry_detail, name='inquiry-detail'),
path('update/<int:pk>/', inquiry_update, name='inquiry-update'),
path('delete/<int:pk>/', inquiry_delete, name='inquiry-delete'),
]
最後に先程空にしておいた削除リンクの部分にURLを指定しておきます。
指定するURLは以下のとおりです。
inquiry_detail.html
{% url 'DjangoApp:inquiry-delete' inquiry.id %}
inquiry_list.html
{% url 'DjangoApp:inquiry-delete' item.id %}
では、試してみましょう。
レコードが消えていることがわかりますね。
CRUD機能の実装については、基本的な部分が一通り完了しました。
この手のページでは、他にも検索機能が必要ですね。
受付データが多くなってくると、対象のデータを探すのが大変です。また、いまのままでは、受付一覧に全登録レコードが表示されてしまいます。数件であれば問題ありませんが、1000件などになってくるとスクロールがどこまで続くのやらといった感じですね。
1ページに表示できるレコード件数を絞るためにページネーションと呼ばれる機能の実装も必須と言っていいでしょう。
次回以降は、検索機能の実装とページネーション機能の実装について見ていきます。
いずれもこれまで通りDjangoに基本機能がもれなく用意されていますのでご安心ください。
コメント