数回前の記事で、CreateView
とUpdateView
について書きました。今回は更新ジェネリックビューの残り、DeleteView
について書きます。CRUD
のD
に相当します。
バージョン等
前回と同様です。
ツール | バージョン |
---|---|
Python | 3.7.2 |
Django | 2.1.7 |
bootstrap | 4.1.3 |
DeleteViewについて
前提:Model層
- models.py
from django.db import models class Table(models.Model): """テーブル一覧""" name = models.CharField(max_length=100) class Column(models.Model): """カラム定義(物理名格納)""" table = models.ForeignKey(Table, on_delete=models.CASCADE) name = models.CharField(max_length=100)
前回と同様ですが、上記二つのModel
を使います。
DeleteViewとは
DeleteView
は、名前の通り要素を削除するビューです。対象が存在したら削除します。が、削除は対象が無くても結果的には成功と言えるので…
DeleteView
では、ビューで指定したモデルの1行を削除することを想定しています。
DeleteViewの定義
DeleteView
は、CreateView
、UpdateView
と異なり、入力する必要が無いです。そのため、考え方か異なります。
説明のために、URLとビューを示します。
- urls.py
from django.urls import path from .views import table app_name = 'inputs' urlpatterns = [ path('table', table.TableListView.as_view(), name='tables'), path('table/<int:pk>', table.TableDetailView.as_view(), name='table'), path('table/<int:pk>/delete', table.TableDeleteView.as_view(), name='table_del'), ]
UpdateView
の場合と同様、URLに主キーを含めます。
- views/table.py
class TableDeleteView(DeleteView): """テーブル削除""" model = Table success_url = reverse_lazy('inputs:tables') template_name = 'inputs/delete.html'
単純な場合、上記の定義のみで良いです。
テンプレートについて
CreateView
等のテンプレートは、入力項目をform
として配置し、そこにsubmit
用のボタン等を置く、という形で作成します。登録するデータを入力するためのテンプレートを渡すことになります。
一方、DeleteView
が要求するテンプレートは、削除確認用途として使われます。ドキュメントにも
確認ページを表示して、現存するオブジェクトを削除するビューです。
という記述の通りです。共通のような形で作ると、以下のようになります。
- templates/delete.html
<!-- body部のみ --> <form method="post"> {% csrf_token %} <p>削除します。よろしいですか?</p> <input class="btn btn-danger" type="submit" value="削除する"> </form>
削除確認のみ行います。
URLに対する役割
DeleteView
のURLに対してリクエストを送った場合、以下の挙動となります。
メソッド | 挙動 |
---|---|
GET | 確認ページを返す |
POST | 指定された要素を削除し、指定したページにリダイレクト |
POSTするには、フォームにsubmit
のボタンを置けばいいです。
雑な図ですが、イメージはこんな感じです。
削除前に情報を表示する
削除する前に、削除されようとしている項目の情報を取得したいとします。
テンプレートにはobject
という名前で削除しようとしているモデルが格納されるので、そちらを使用できます。
<form method="post"> {% csrf_token %} <p>このテーブルを削除しますか?</p> <table class="table table-sm table-bordered table-responsive"> <tbody> <tr> <th>ID</th> <td>{{ object.id }}</td> </tr> <tr> <th>テーブル名</th> <td>{{ object.name }}</td> </tr> </tbody> </table> <input class="btn btn-danger" type="submit" value="削除する"> </form>
また、ここでは載せませんが、get_queryset
やget_context_data
をオーバーライドして、追加データを取得することもできます。
削除時の子要素
削除する際は、その要素の主キーを指定します。
今回、Column
はTable
を外部キー要素として指定しています。もし、Table
を削除する場合、そのTable
を参照しているColumn
があると、通常は先にColumn
を消す必要があります。
今回は、親が消された場合、子も一緒に消えるように、
class Column(models.Model): """カラム定義(物理名格納)""" table = models.ForeignKey(Table, on_delete=models.CASCADE) name = models.CharField(max_length=100)
ForeignKey
を作成する際にon_delete=models.CASCADE
を指定しています。なので気にせず消せます*1。
on_delete
に関しては、こちらに記載があります。
参考
次回
ジェネリックビューを使わない場合について、書く予定です。今回書く予定でしたが、分量が多かったため、改めて書きます。
おわりに
Django
は、単純なCRUD
だけならとても簡単に作成できます。問題はそこから逸脱し始めるときです。そのあたりを次回書いてみます。
*1:場合によっては多くの行が消えるため、一応パフォーマンス上の考慮は必要