このページでは、Django フレームワークで定義される DeleteView
の使い方について説明していきます。
この DeleteView
は View
というクラスのサブクラスの1つであり、ビューをクラスベースで作成する際に利用するクラスとなります。この View のサブクラス
を継承し、さらにクラス変数を定義したりメソッドをオーバーライドすることで、あなたが開発したいアプリに応じたビューを作成することが可能となります。
この辺りのクラスベースビューやクラスベースビューの作り方については下記ページで解説していますので、詳しくはこちらをご参照ください。
【Django入門15】クラスベースビューの基本また、この DeleteView
は、View のサブクラス
である DetailView
と関連性が高いです。DetailView
に関しては下記ページで解説していますので、事前に下記ページを読んでいただくことをオススメします。
イメージとしては、DeleteView
は DetailView
に削除機能を追加したような View のサブクラス
のサブクラスとなります。この2つのクラスの名前が多少似ているので、これらを混同しないように読み進めていただければと思います。
Contents
DeleteView
では、DeleteView
について解説していきたいと思います。
DeleteView
は、名前の通り、データベースに既に保存されているレコードの削除を実現する View のサブクラス
となります。
DeleteView
は django.views.generic
から import
して利用します。
from django.views.generic import DeleteView
例えば、会員の退会、投稿済みのコメントの削除、データベースに保存されているレコードを削除を実現するのが DeleteView
となります。
削除が行われるのは POST
リクエスト時
この DeleteView
では POST
リクエストを受け取った際にデータベースからのインスタンス(レコード)の削除が行われるようになっています。
もう少し具体的に説明すると、DeleteView
では、POST
リクエストを受け取った際に URL で指定される「プライマリーキー」や「スラッグ」を持つインスタンス(レコード)を1つデータベースから取得します。ここで取得されるのが削除対象のインスタンスとなります。そして、その取得インスタンスに delete
メソッドを実行させることで、そのインスタンスをデータベースから削除するようになっています。
また、上の図では省略していますが、インスタンスの削除に成功した際には他のページへのリダイレクトレスポンスが返却されることになります。
この削除対象のインスタンスの取得は DeleteView
の get_object
というメソッドによって実施されます。この get_object
メソッドは DetailView
も持っており、両方で全く同じメソッドとなっています。なので、DeleteView
がリクエストを受け取った際にデータベースから1つのインスタンスの取得を行う仕組みに関しては DeleteView
と同じで、その仕組みに関しては下記ページで解説していますので、詳細を知りたい方は下記ページを参照していただければと思います。
ここで重要なのは、DeleteView
では POST
リクエストを受け取った際に目的のデータベースからのインスタンスの削除が行われるという点になります。
スポンサーリンク
GET
リクエスト時には削除確認のページを表示
では、DeleteView
が GET
リクエストを受け取った際には何が行われるのでしょうか?
GET
リクエストを受け取った際には、DeleteView
では削除確認用のページの表示が行われるようになっています。あなたもウェブアプリを利用していて何かの削除や退会の申請をしようとした際に「本当に削除しても良いですか?」「本当に退会しますか?」のようなメッセージが表示された経験があるのではないかと思います。こういった削除確認用のページの表示を行うのが、GET
リクエストを受け取った際の DeleteView
の動作となります。
で、この時には削除対象となっているインスタンスの詳細情報を表示することが多いです。削除対象となっているインスタンスの情報を表示した上で、ユーザーに削除の確認を行います。
そのため、DeleteView
では GET
リクエストを受け取った際にも get_object
メソッドによりデータベースから削除対象となるインスタンスを取得するようになっています。そして、そのインスタンスの詳細情報をページとして表示します。で、この時の動作は基本的には DetailView
と同じです。なので、DeleteView
を理解する上では DetailView
についてまず理解しておいた方が良いですし、DetailView
が使いこなせれば DeleteView
も簡単に使いこなすことができます。
ただ、DetailView
では単にデータベースから取得したインスタンスの情報を表示するだけでしたが、DetailView
の場合は、データベースから取得したインスタンスの情報を表示するだけでなく、削除を実行するためのボタン等をページに表示する必要があります。
そして、このボタンが押された際には DeleteView
に対して POST
リクエストが送信されるようにテンプレートファイルや urls.py
を準備しておく必要があります。
こうしておけば、まず GET
リクエストを受け取った DeleteView
が削除対象のインスタンスの情報を表示するためのページの HTML をレスポンスとしてクライアントに返却し、さらにボタン等で削除の実行が行われた際には DeleteView
が POST
リクエストを受け取って実際にデータベースからインスタンスの削除を行うような流れを実現することができるようになります。
もちろん、削除前のユーザーへの削除の確認が不要というのであれば、直接 DeleteView
に POST
リクエストを送信するようなアプリのページ構成にするようなことも可能です。例えば、インスタンスの一覧ページに削除ボタンを設け、このボタンが押された時に DeleteView
に対して POST
リクエストが送信されるようにしてやれば、ユーザーへの削除の確認を行わずに直でデータベースからのインスタンスの削除を行うことも可能です。
ただ、ユーザーが間違って削除してしまう可能性もあるので、削除確認用のページは表示した方が良いと思います。いずれにせよ、DeleteView
では GET
リクエストを受け取った際に削除確認用のページを表示し、POST
リクエストを受け取った際にデータベースからのインスタンスの削除が行われるということは覚えておきましょう!
DeleteView
でのクラスベースビューの作り方
では、次は DeleteView
でクラスベースビューを作成する手順について説明していきます。
DeleteView
でのクラスベースビューの作り方に関しても他の View のサブクラス
とほぼと同様となります。
つまり、views.py
に DeleteView
を継承するクラスを定義し、そのクラスでクラス変数やメソッドを定義して DeleteView
側で定義されているクラス変数の上書き・メソッドのオーバーライドを行なうことで、ビューを作成していきます。これにより、DeleteView
の特徴を活かしながら自身のウェブアプリに応じたビューにカスタマイズしていくことが可能となります。
また、DeleteView
では GET
リクエスト受けとった際に get
メソッドが、POST
リクエストを受け取った際に post
メソッドが実行されるようになっています。そして、前述のように、これらのメソッドが実行された際に、削除確認ページが表示されたりデータベースからのインスタンスの削除が行われるようになっています。
そして、DeleteView
のクラス変数や他のメソッドは、これらの get
メソッドおよび post
メソッドから利用されるようになっています。したがって、DeleteView
のサブクラス側でクラス変数やメソッドを上書き・オーバーライドしてやれば、この get
メソッドと post
メソッドの動作を変化させることができます。
クラス変数 model
のモデルクラスを指定する
ここまで説明してきた通り、DeleteView
は特定のテーブルからレコードを削除するためのビューですので、そのレコードの削除先となるテーブルの指定が必要となります。そのため、DeleteView
を継承するクラスを定義する際には、クラス変数 model
を定義して削除先のテーブルを指すモデルクラスを指定することが必須となります(Django においてはデータベースのテーブルはモデルクラスとして扱われる)。
スポンサーリンク
削除対象のインスタンスの情報を表示する
また、前述の通り、GET
リクエストを受け取った際に実行される get
メソッドでは、ユーザーに「本当に削除を実行しても良いのか」を判断させるための情報を表示すること、および、削除を実行するためのボタン等を表示することが重要となります。そして、そのボタン等がクリックされた際には DeleteView
のサブクラスに POST
リクエストを送信することが必要です。
また、ユーザーに「本当に削除しても良いのか」を判断してもらうためには、削除対象のインスタンスの情報を表示することが必要です。これに関しては DetailView
と同じ仕組みで表示することが可能で、DetailView
に関しては下記ページで解説していますので詳細はこちらを参照していただければと思います。前述の通り、DeletelView
を継承するクラスではクラス変数 model
の定義が必須であり、削除対象のインスタンスの取得先もクラス変数 model
に指定されたモデルクラス(テーブル)となります。
ポイントは、”削除対象のインスタンスを特定するための情報を指定できるように urls.py
を作成” し、”その情報を受け取れるように DeleteView
のサブクラスでクラス変数を定義” し、さらには “削除対象のインスタンスの情報を表示できるようにテンプレートファイルを作成” するという点になります。
要は、ビューとビュー以外の部分で話が合うように、それぞれのファイルを実装していく必要があります。この「ビューとビュー以外の部分で話が合うように実装する」という点はクラスベースでビューを作成していく上で重要なポイントになりますので、ここはしっかり意識しながら開発を進めるようにしていきましょう!
削除実行ボタンを表示する
また、POST
リクエストを送信するボタンの作り方に関しては下記のフォームの解説ページで詳細を説明しています。
要は、テンプレートファイルで <form>
〜 </form>
の間にボタン要素となるタグを記述し、form
タグの action
属性に DeleteView
のサブクラスに紐付けられた URL を指定し、さらに form
タグの method
属性に post
を指定してやれば良いだけです。例えば DeleteView
のサブクラスから利用されるテンプレートファイルに下記のようなタグを記述しておけば、クリックすると DeleteView
のサブクラスに POST
リクエストを送信するボタンがページに表示されるようになります。
<form action="{% url 'delete' object.id %}" method="post">
{% csrf_token %}
<p><input type="submit" value="削除"></p>
</form>
上記は url.py
で DeleteView
のサブクラスと 'delete'
という名前が関連付けられていることを前提としたものとなっている点に注意してください。
また、 object
は削除対象となるインスタンスを参照するための変数です。DeleteView
が生成するコンテキストには 'object'
キーにデータベースから取得したインスタンスがセットされるようになっています。この辺りに関しては後述の DeleteView が生成するコンテキスト で詳細を説明します。
こんな感じで、GET
リクエストを受け取った際には削除対象のインスタンスを取得して表示することと、削除実行ボタンを表示することが重要になります。そして、前者に関しては DetailView
と同様の手順で実現可能です。また、後者に関しては通常のフォームを扱う時と同様にテンプレートファイルを用意しておくことが必要となります。ただし、フォームに入力フィールドなどを用意することは必須ではありません。逆に言えば、入力フィールドを表示することも可能です。これに関しては後述の form_class で解説します。
リダイレクト先を設定する
で、上記のようなボタンを用意しておけば、ユーザーがインスタンスを削除したいと判断した際にボタンがクリックされ、DeleteView
のサブクラスに POST
リクエストが送信されることになります。そして、これにより DeleteView
の post
メソッドが実行され、データベースからのインスタンスの削除が行われることになります。
データベースからのインスタンスの削除が行われた後には、CreateView
や UpdateView
と同様に、他の URL へのリダイレクトが行われることになります。そのため、DeleteView
のサブクラスではリダイレクト先の URL を設定しておくことが必要になります。
このリダイレクト先の URL の設定に関しては下記の CreateView
の解説ページで詳細を説明していますので、詳しくは下記ページをご参照いただければと思います。
DeleteView
の場合は、クラス変数 success_url
の定義によってリダイレクト先の URL を指定することが多いと思います。
スポンサーリンク
DeleteView
のクラス変数
では、次は DeleteView
で定義されているクラス変数の紹介を行なっていきます。先ほど触れた success_url
も DeleteView
で定義されているクラス変数の1つで、これらのクラス変数を DeleteView
を継承するクラスで定義し直して上書きすることでクラスの動作のカスタマイズを行うことが可能となります。
DeleteView
の場合、GET
メソッドのリクエストを受け取った際に get
メソッドが実行され、GET
メソッドのリクエストを受け取った際に post
メソッドが実行されることになるため、これらの get
メソッドや post
メソッドの動作を変化させることを目的にクラス変数の定義を行なっていくことになります。
ただ、ここまでにも説明したように、DeleteView
は削除対象となるインスタンスの表示や、削除対象となるインスタンスのデータベースからの取得は DetailView
と同様の仕組みで実現されており、その中で DetailView
でも定義されているクラス変数が利用されるようになっています。また、DeleteView
ではフォームを扱うこともでき、このフォームを扱う仕組みは CreateView
と同様です。そして、この際には CreateView
でも同様に定義されているクラス変数が利用されます。
で、DetailView
や CreateView
で定義されているクラス変数に関しては、これらの解説ページで既に説明済みです。したがって、DetailView
や CreateView
と全く同じ意味合いとなるクラス変数に関しては、下記ページにおける、それらのクラス変数の解説を行なっている節へのリンクのみを紹介するようにしたいと思います。この点はご了承ください。
DeleteView
のクラス変数の一覧
この DeleteView
で定義されるクラス変数には下記のようなものが存在します。
- form_class
- success_url (
CreateView
) - fields (
CreateView
) - initial (
CreateView
) - prefix (
CreateView
) - template_name (
CreateView
) - template_name_suffix
- model (
DetailView
) - queryset (
DetailView
) - pk_url_kwarg
DetailView
) - slug_url_kwarg (
DetailView
) - slug_field (
DetailView
) - context_object_name (
DetailView
) - extra_context (
ListView
) - template_engine (
ListView
) - response_class (
ListView
) - content_type (
ListView
)
各リンクをクリックすれば括弧内に示した View のサブクラス
の解説ページにジャンプするようにしています。基本的に、フォームを扱うための設定を行うクラス変数に関しては CreateView
の解説ページ、インスタンスを1つのみ取得して表示を行うための設定を行うクラス変数に関しては DetailView
の解説ページ、その他のクラス変数に関しては ListView
の解説ページにジャンプするようにしています。
ここでは、form_class
と template_name_suffix
のみの説明を行なっていきます。これらも CreateView
や DetailView
で定義されているクラス変数ではあるのですが、役割や初期値が異なるため、別途説明させていただくことにしています。
form_class
form_class
は DeleteView
で扱うフォームクラスを指定するクラス変数となります。このクラス変数自体は CreateView
や UpdateView
にも存在するのですが、少し役割が異なります。
CreateView
や UpdateView
はデータベースにインスタンスを保存するための View のサブクラス
であり、その保存対象となるインスタンスの情報の入力受付を行うためのフォームクラスを指定するために form_class
を定義する必要があります。そして、それらのフィールドにユーザーが入力した情報に基づいてインスタンスがデータベースに保存されることになります。
ですが、DeleteView
の場合、同様の目的で form_class
の定義を行うことは無意味です。なぜなら、同様の目的で form_class
の定義をしてデータベースにインスタンスを保存するための情報の入力受付を行なったとしても、その情報を DeleteView
のサブクラスが受け取った際に、そのインスタンスがデータベースから削除されることになるためです。
なので、削除対象となるインスタンスの情報の入力を受け付けるのではなく、別の目的の入力受付を行うために form_class
の定義を行うことになります。例えば私が思いつくのは「削除の理由の入力受付」です。
データベースからのインスタンスの削除を行う例の代表の1つはユーザーの退会になります。ボタンのクリック等で単に退会を受け付けるだけでも良いのですが、削除確認ページに入力フィールドを用意し、そこに退会理由などを記入してもらうようにして貰えばデータベースにユーザーの退会理由などを蓄積していくことができるようになります。そして、その理由を参考にしてアプリ等の運営の仕方の改善などを図ることができるようになります。
このように、DeleteView
のサブクラスではフォームを扱うことができ、そのフォームは削除対象のインスタンスの情報を入力受付を行うのではなく、他の目的を実現するために扱うことは覚えておくと良いと思います。
実装例に関しては、DeleteView の利用例 で紹介したいと思います。
スポンサーリンク
template_name_suffix
template_name_suffix
に関してはクラス変数の意味合いとしては他のクラス同様です。クラス変数 template_name
を定義しなかったときに View のサブクラス
が利用するテンプレートファイルのデフォルトのパスにおけるサフィックス(末尾側の文字列)を指定するクラス変数となります。
DeleteView
においては、この template_name_suffix
のデフォルトは 'confirm_delete'
となります。そして、template_name
が定義されていない場合のテンプレートファイルのパスはクラス変数 model
に指定したモデルクラスの モデルクラス名
(小文字) とを組み合わせて下記のように決まります。そして、このテンプレートファイルが利用されて GET
リクエスト受信時には削除確認用のページ表示が行われることになります。
モデルクラス名_confirm_delete.html
このテンプレートファイルのパスからも、DeleteView
では GET
リクエストを受け取った際には削除確認用のページが表示される作りになっていることが確認できると思います。
DeleteView
のメソッド
次に DeleteView
の持つメソッドを紹介していきます。DeleteView
を継承したクラスを定義し、そのクラスで DeleteView
の持つメソッドをオーバーライドしてやることで DeleteView
とは異なる動作のクラスを実現することができるようになります。
DeleteView
のメソッド一覧
DeleteView
の持つメソッドの一覧は下記のようになります。あくまでもクラスのカスタマイズ目的でオーバーライドを行う可能性のあるものを挙げており、as_view
などのカスタマイズは行わないであろうメソッドは省略しています。
また、DeleteView
は get
メソッドと post
メソッドを持っており、メソッドが GET
のリクエストを受け取った場合は get
が実行され、メソッドが POST
のリクエストを受け取った場合は post
が実行されようになっています。そして、これらの get
や post
の中から各種メソッドが実行されるようになっています。
get
:リクエストのメソッドがGET
の場合の処理を実行するpost
:リクエストのメソッドがPOST
の場合の処理を実行するget_context_data
:テンプレートに渡すコンテキストを生成するget_form
:フォームクラスのインスタンスを取得するget_form_class
:フォームクラスを取得するget_form_kwargs
:フォームクラスのコンストラクタに指定するパラメータを取得するget_initial
:initial
への指定値を取得するget_prefix
:prefix
への指定値を取得するform_valid
:データベースに保存してあるレコード・インスタンスを削除し、特定の URL へのリダイレクトレスポンスを返却する(妥当性の検証が OK の時に実行される)form_invalid
:再度フォームを表示する(妥当性の検証が NG の時に実行される)get_success_url
:リダイレクト先の URL を取得するget_template_names
:テンプレートファイルの名前を取得するrender_to_response
:レスポンスを返却するget_context_object_name
:context_object_name
への指定値を取得するget_queryset
:インスタンスの集合(クエリセット)を取得するget_object
:インスタンスを取得するget_slug_field
:slug_field
を取得する
オーバーライドする機会の多いメソッドは form_valid
になると思います。CreateView
や UpdateView
の場合は get_success_url
もオーバーライドする機会が多いですが、これは新規登録したインスタンスや更新したインスタンスに応じてリダイレクト先の URL を動的に変化させたいケースが多いためです。DeleteView
の場合、削除したインスタンスの情報を表示するようなことは少ないため、動的にリダイレクト先の URL を変化させる機会は少ないかもしれません。それでも get_success_url
をオーバーライドしたい場合は、CreateView
の解説ページで get _success_url
のオーバーライド例を紹介していますので、下記ページを参照していただければと思います。
form_valid
ここでは form_valid
のオーバーライドについてのみ説明を行いたいと思います。
form_valid
は先程触れた get_success_url
同様に CreateView
や UpdateView
でも定義されているメソッドになります。そして、これも CreateView
や UpdateView
同様に、フォームから送信されてきたデータの妥当性の検証結果が OK の場合に実行されるメソッドになります。
CreateView
や UpdateView
の場合は、これらのビューの中で利用されるフォームクラスを指定するクラス変数(form_class
or model
+ fields
)の定義が必須ですが、DeleteView
の場合は必須ではなく定義は任意となります
これらのクラス変数が定義されていない場合、DeleteView
では利用されるフォームクラスが Form
というクラスに自動的に設定されるようになっています
そして、この場合は必ず妥当性の検証結果が OK となります
ただし、メソッド内部で行われる処理が若干異なるので注意が必要です。
DeleteView
の form_valid
で行われるのは下記の3つの処理のみとなります。2つ目の処理によって目的のデータベースからのインスタンスの削除が行われることになります。
- リダイレクト先の URL の取得
- データベースからのインスタンスの削除
- 取得した URL へのリダイレクトレスポンスの返却
インスタンスの削除を行うだけであれば上記の処理のみで問題ないです。ですが、form_class で説明したように DeleteView
でもフォームを扱うことができ、フォームから送信されてきたデータをデータベースにインスタンス(レコード)として保存したいような場合は、上記の処理しか行われない form_valid
では不十分ということになります。こういった、妥当性の検証結果が OK の場合に実行したい処理が DeleteView
の form_valid
では不十分である場合は、DeleteView
のサブクラス側で form_valid
を定義してオーバーライドする必要があります。
オーバーライドのやり方自体は下記ページでも解説していますので、ここでの詳細な説明は省略しますが、DeleteView の利用例 ではフォームから送信してきたデータをデータベースにインスタンスとして保存する例を示したいと思います。
【Django】CreateViewの使い方(クラスベースビューでの新規登録ページの実現)スポンサーリンク
DeleteView
が生成するコンテキスト
続いて DeleteView
が生成するコンテキストについて説明しておきます。
DeleteView
の場合、コンテキストは、削除確認用のページを表示するための HTML を生成する際に利用されます。この HTML が生成されるのは、GET
リクエストを受け取った時と、POST
リクエストを受け取ったものの、送信されてきたデータの妥当性の検証結果が NG であった時です(後者に関しては、ユーザーにフォームへのデータの再入力をしてもらうためにページを表示する)。
そして、DeleteView
が生成するコンテキストには下記の要素が含まれることになります。上側の2つに関しては DetailView
が生成するコンテキストにも含まれるキーとなり、それに 'form'
が追加された形のコンテキストが生成されることになります。
'object'
: データベースから取得されたインスタンスcontext_object_name
: データベースから取得されたインスタンス'form'
: フォームクラスのインスタンス
context_object_name
に関しては、DetailView
の解説ページの context_object_name で説明したように、クラス変数の定義で変更することも可能です。デフォルトは モデルクラス名
(小文字) となっています。モデルクラス名が Comment
であれば 'comment'
となります。
コンテキストには 'form'
が含まれることになりますが、基本的にテンプレートファイルから form
を参照するのは、DeleteView
のサブクラスでクラス変数 form_class
を定義している場合のみとなります。form_class
を定義しない場合は Django フレームワークで定義される Form
というクラスのインスタンスがコンテキストの 'form'
キーにセットされることになりますが、このクラスではフィールドが定義されていないため、テンプレートファイルで form
を出力してもページとしては何も表示されません。
上記の3つ以外のデータをコンテキストにセットしてテンプレートファイルから参照できるようにしたい場合は、ListView
の解説ページの extra_context で説明しているクラス変数 extra_context
を定義したり、get_context_data
のオーバーライドを行なったりしてコンテキストの要素を追加する必要があります。
DeleteView
の利用例
最後に、ここまでの説明のまとめとして、DeleteView
を継承するクラスでのビューの作成例を示していきたいと思います。
プロジェクトとアプリの作成の手順に関しては下記ページの ListView の利用例 と同じとなりますので、ここでは説明を省略させていただきます。ListView
の解説ページの利用例を読んでいない方は、下記ページの プロジェクトとアプリの作成 を読んで手順を進めていただければと思います。
モデルの作成とマイグレーション
プロジェクトとアプリの作成の次は、models.py
を変更してモデルクラスの定義を行なっていきます。
今回は、下記のように forum
フォルダ内の models.py
を変更してモデルクラスの定義を行いたいと思います。
from django.db import models
class Comment(models.Model):
text = models.CharField(max_length=256)
class Reason(models.Model):
text = models.CharField(max_length=256)
Comment
は掲示板アプリ等に投稿されたコメントを管理するテーブル、Reason
はコメントの削除理由を管理するテーブルとして扱っていきます。このアプリでの削除対象は Comment
のインスタンスとなります。
models.py
の変更後は、models.py
に定義したモデルクラスに対応するテーブルをデータベースに作成します。テーブルは下記の2つのコマンドでマイグレーションを実施することで作成することができます。
% python manage.py makemigrations % python manage.py migrate
スポンサーリンク
フォームの定義
続いてフォームクラスの定義を行なっていきます。
forum
フォルダの下に forms.py
というファイルを新規作成し、その forms.py
の中身を下記のように変更して保存してください。
from django import forms
from .models import Comment, Reason
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text', ]
class ReasonForm(forms.ModelForm):
class Meta:
model = Reason
fields = ['text', ]
今回は2つのフォームクラスの定義を行なっています。1つ目が CommentForm
で、このフォームは DeleteView
ではなく CreateView
のサブクラスで利用するフォームであり、コメントの新規投稿フォームの役割を果たすフォームとなります。
2つ目が ReasonForm
で、DeleteView
のサブクラスで本フォームを利用し、コメント削除時に削除理由を入力できるようにするためのフォームとなります。
クラスベースビューの作成
続いて、本題のクラスベースビューの作成を行っていきます。今回は、ここまでの説明の通り DeleteView
を継承するクラスを定義し、そのクラスをクラス変数の定義とメソッドのオーバーライドによってカスタマイズしていきます。
また、DeleteView
はデータベースからのインスタンスを削除するビューとなりますので、事前に削除対象となるインスタンスをデータベースに新規登録するために CreateView
のサブクラスの定義も行います。さらに、Comment
や Reason
のインスタンスの一覧を表示できるよう、ListView
のサブクラスの定義も行っていきたいと思います。
これらを定義した views.py
の例は下記のようになります。
from django.views.generic import ListView, CreateView, DeleteView
from .models import Comment, Reason
from .forms import CommentForm, ReasonForm
from django.urls import reverse_lazy
class CommentDelete(DeleteView):
model = Comment
form_class = ReasonForm
success_url = reverse_lazy('comments')
pk_url_kwarg = 'comment_id'
def form_valid(self, form):
form.save()
return super().form_valid(form)
class CommentCreate(CreateView):
form_class = CommentForm
model = Comment
success_url = reverse_lazy('comments')
class CommentList(ListView):
model = Comment
class ReasonList(ListView):
model = Reason
この views.py
においては4つのクラスを定義しています。
まず、CommentList
と ReasonList
はそれぞれ Comment
と Reason
のインスタンス一覧の表示を実現する ListView
のサブクラスとなります。ListView
に関しては下記ページで解説していますので、詳細に関しては下記ページを参照してください。
また、 CommentCreate
はコメントの新規投稿(Comment
のインスタンスのデータベースへの新規登録)を実現する CreateView
のサブクラスとなります。CreateView
に関しては下記ページで解説していますので、詳細に関しては下記ページを参照してください。
そして、CommentDelete
はデータベースからのインスタンスの削除を実現するクラスとなります。この CommentDelete
こそが、このページで解説している DeleteView
のサブクラスとなります。
CommentDelete
ではクラス変数 model
に Comment
を指定しているため、このクラスで削除するインスタンスは Comment
クラスのインスタンスとなります。削除確認ページに詳細を表示するインスタンスも Comment
クラスのインスタンスとなります。
また、クラス変数 form_class
を定義して ReasonForm
を指定しているため、DeleteView が生成するコンテキスト で説明したように、コメントの削除理由を入力するフィールドを持つ ReasonForm
のインスタンスがテンプレートファイルから参照可能となります。後述で紹介するテンプレートファイルでは、このフォームを表示してユーザーからのコメントの削除理由の入力受付を行うようにしていきます。
さらに、CommentDelete
では form_valid
メソッドのオーバーライドを行なっており、この form_valid
における form.save()
で、削除確認用ページから送信されてきたデータが ReasonForm
のベースとなっているモデルクラスのインスタンス(レコード)、つまり Reason
のインスタンスとしてデータベースに保存されることになります。
その他にもクラス変数 pk_url_kwarg
やクラス変数 success_url
の定義も行っていますが、これらのクラス変数の詳細についてはは、前者に関しては下記ページを、
後者に関しては下記ページを参照していただければと思います。
【Django】CreateViewの使い方(クラスベースビューでの新規登録ページの実現)ここまでの説明のように、DeleteView
のサブクラスでは単に削除確認用のページを表示するだけでなく、form_class
を定義することでユーザーからの入力受付を行うことも可能となります。そして、form_valid
のオーバーライドによって、それをデータベースに保存することが可能です。form_valid
のオーバーライドの仕方によっては、削除時にメールを送信するようなことも可能となります。
ビューと URL とのマッピング
次は views.py
で定義したビューと URL とのマッピングを行なっていきます。
まず、classviewproject
フォルダの下にある urls.py
を下記のように変更してください。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('forum/', include('forum.urls')),
]
続いて、forum
フォルダの下に urls.py
を新規作成し、中身を下記のように変更してください。
from django.urls import path
from . import views
urlpatterns = [
path('delete/<int:comment_id>/', views.CommentDelete.as_view(), name='delete'),
path('create/', views.CommentCreate.as_view(), name='create'),
path('comments/', views.CommentList.as_view(), name='comments'),
path('reasons/', views.ReasonList.as_view()),
]
ポイントは urlpatterns
の第1要素になります。
上記のように要素を指定しておくことで、ルートパス指定で /forum/delete/<int:comment_id>/
へのリクエストがあった際に CommentDelete
が動作するようになります。この <int:comment_id>
部分には、削除対象となるインスタンスに割り当てられたプライマリーキーを指定する必要があります。そして、CommentDelete
では、ここで指定されたプライマリーキーが割り当てられているインスタンスがデータベースから取得され、そのインスタンスの表示や削除が行われることになります。
スポンサーリンク
テンプレートの作成
次はテンプレートファイルを作成していきます。ソースコードの変更としては、これが最後となります。
今回 views.py
で定義した各クラスではクラス変数 template_name
を定義していないため、各クラスのデフォルト設定のパスに存在するテンプレートファイルが各クラスで利用されることになります。
具体的に言うと、各クラスで利用されるテンプレートファイルは下記のパスのものとなります。なので、下記のパスにテンプレートファイルを用意していくことになります。
CommentDelete
:'forum/comment_confirm_delete.html'
CommentCreate
:'forum/comment_form.html'
CommentList
:'forum/comment_list.html'
ReasonList
:'forum/reason_list.html'
これらのパスは、アプリフォルダの templates
フォルダから見た相対パスとなりますので、まずはアプリフォルダ(forum
フォルダ)の中に templates
フォルダを作成し、さらにその templates
フォルダの中に forum
フォルダを作成しておきましょう。この最後に作成した forum
フォルダの中に、各クラスが利用するテンプレートファイルを1つ1つ作成していきます。
comment_confirm_delete.html
まずは、CommentDelete
から利用される comment_confirm_delete.html
を作成します。
先程作成した forum
フォルダの中に comment_confirm_delete.html
を新規作成し、中身を下記のように変更して保存してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of DeleteView</title>
</head>
<body>
<main>
<h2>コメントの削除</h2>
<p>下記のコメントを削除してもよろしいですか?</p>
<table>
<tbody>
<tr><td>ID :</td><td>{{ comment.id }}</td></tr>
<tr><td>TEXT :</td><td>{{ comment.text }}</td></tr>
</tbody>
</table>
<p>削除理由を教えてください</p>
<form action="{% url 'delete' object.id %}" method="post">
{% csrf_token %}
<table>{{ form.as_table }}</table>
<p><input type="submit" value="削除"></p>
</form>
</main>
</body>
</html>
このテンプレートファイルは、CommentDelete
が GET
リクエストを受け取った際 or POST
リクエストを受け取ったものの送信されてきたデータの妥当性の検証結果が NG の際に利用されるテンプレートファイルとなります。
このテンプレートファイルは削除対象のインスタンスの情報を表示するとともに、ユーザーからの削除実行を受け付けるための HTML を生成するために利用されます。そして、これらが実現できるように、このテンプレートファイルではコンテキストとして受け取った comment
の情報の表示(データ属性 id
と text
の出力)とボタン要素の表示を行うようにしています。
また、CommentDelete
では class_form
に ReasonForm
を指定しているため、テンプレートファイルからは変数名 form
で ReasonForm
のインスタンスを参照することができ、これを {{ form.as_table }}
で出力することで ReasonForm
の持つフィールド、すなわち削除理由の入力フィールドをページに表示しています。
このように、ユーザーに削除対象のインスタンスの情報示すだけでなく、削除を実行するためのボタンが行えるようにテンプレートファイルを作成する必要があるという点が、DeleteView
のサブクラスを使いこなす上でのポイントの1つとなります。また、上記のテンプレートファイルのように、何らかの情報の入力受付を行うためのフォームも表示可能であることも覚えておきましょう。
comment_form.html
続いて他のテンプレートファイルを作成していきます。
CommentCreate
から利用される comment_form.html
には下記のようなものを用意したいと思います。単純にフォームを表示するだけのテンプレートファイルであり、このテンプレートファイルから参照する form
は CommentForm
のインスタンスとなり、comment_confirm_delete.html
から参照する form
とは異なるものであることに注意してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of CreateView</title>
</head>
<body>
<main>
<h2>コメントの投稿</h2>
<form action="{% url 'create' %}" method="post">
{% csrf_token %}
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
</main>
</body>
</html>
comment_list.html
また、CommentList
から利用される comment_list.html
には下記のようなものを用意したいと思います。基本的には CommentList
のクラス変数 model
で指定されるモデルクラスのインスタンスの一覧を表示するためのテンプレートファイルとなりますが、各インスタンスの右側には 削除
リンクを表示するようにしています。そして、この 削除
リンクをユーザーがクリックすれば、{% url 'delete' object.id %}
によって解決される URL、すなわち、そのインスタンスの削除確認用のページが表示されるようにしています(Comment
クラスにおいて、object.id
はインスタンスのプライマリーキーとなります)。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of ListView</title>
</head>
<body>
<main>
<h2>コメント一覧</h2>
<table>
<thead>
<tr>
<th>ID</th><th>text</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<td>{{ object.id }}</td>
<td>{{ object.text }}</td>
<td><a href="{% url 'delete' object.id %}">削除</a></td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
</body>
</html>
reason_list.html
最後に、ReasonList
から利用される reason_list.html
を用意していきます。この reason_list.html
は下記のようなものにしたいと思います。単純に、ReasonList
のクラス変数 model
で指定されるモデルクラスのインスタンスの一覧を表示するだけのテンプレートファイルになっています。。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of ListView</title>
</head>
<body>
<main>
<h2>削除理由一覧</h2>
<table>
<thead>
<tr>
<th>ID</th><th>text</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<td>{{ object.id }}</td>
<td>{{ object.text }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
</body>
</html>
動作確認
最後に動作確認を行なっておきましょう!
今回は Comment
のインスタンスの削除が正常に行えることを確認することが動作確認の目的となりますが、まずはその前にインスタンスのデータベースへの新規登録を行う必要があります。そのため、インスタンスのデータベースへの新規登録を行なったとに削除の動作確認を行なっていきます。
最初に、manage.py
が存在するフォルダで下記コマンドを実行します。
% python manage.py runserver
これにより、開発用ウェブサーバーが起動しますので、ウェブブラウザから作成したアプリのページを表示することが可能となります。
次に下記 URL をウェブブラウザで表示してみましょう!
http://localhost:8000/forum/create/
この URL をウェブブラウザで表示すれば下図のような text
の入力フィールドを持つフォームが表示されるはずです。これは CommentCreate
によって表示されるコメントの投稿フォームとなります。
表示されたフォームで適当な半角英数字の文字列を text
に入力して 送信
ボタンを押せば、これらのフィールドに入力されたデータが対応するフィールドにセットされ、さらに id
(プライマリーキー) が自動的にセットされた Comment
のインスタンスがデータベースに新規登録されることになります。
さらにデータベースへの新規登録後に urls.py
によって名前が 'comments'
である URL にリダイレクトが行われ、今度は CommentList
が動作してコメントの一覧が表示されるはずです。といっても表示されるコメントは先程新規登録したコメント1つのみになると思います。先程のコメントの新規投稿フォームを再度表示してコメントの投稿を新たに行うことで、コメント一覧に表示されるコメントの数が増えていくことも確認することができるはずです。
次は、コメント一覧から削除したコメントの右側にある 削除
リンクをクリックしてみましょう!これにより、GET
リクエストを DeleteView
が受け取り、下の図のようなコメントの削除確認用のページが表示されるはずです。
このページでは ReasonForm
のインスタンスの出力によって ReasonForm
のインスタンスの持つフィールド(text
)が表示されていることが確認できると思います。そこに適当な理由を入力して 削除
ボタンをクリックしてみましょう!
このボタンのクリックによって今度は POST
リクエストを DeleteView
が受け取り、まずはフォームから送信されたデータが Reason
のインスタンスとしてデータベースに新規登録されることになります。続いて先程削除確認用のページに表示されたインスタンスがデータベースから削除され、さらにリダイレクトによって再びコメント一覧ページが表示されることになります。
そして、そのコメント一覧ページからは先程削除したインスタンスの表示がなくなっていることが確認できると思います。これにより、今回定義した CommentDelete
によってデータベースからのインスタンスの削除が実現できていることが確認できたことになります!
さらに、今度は下記 URL をウェブブラウザで表示してみましょう。
http://localhost:8000/forum/reasons/
これにより、今度はインスタンスの削除理由の一覧ページが表示されることになります。これは ReasonList
によって表示されるページであり、一覧に表示されるインスタンスは先程 DeleteView
によってデータベースに新規登録された Reason
のインスタンスとなります。先程削除確認用のページで入力した削除理由が表示されていることが確認できるはずです。
今回は削除したインスタンスがコメントに対応するものでしたが、例えばユーザーのインスタンスの削除によってウェブアプリの会員の退会を実現した場合、ユーザーから退会理由を集計することができ、それによって今後のウェブアプリの運営の仕方を改善し、よりよりウェブアプリに仕立てていくこともできると思います1
まとめ
このページでは、DeleteView
および DeleteView
を継承したクラスベースビューの作り方について解説しました!
DeleteView
はデータベースに既に保存されているインスタンス(レコード)を削除するための View のサブクラス
であり、このクラスを継承することで、ユーザーのアプリや SNS 等からの退会や投稿済みのコメントの削除等を行うページを簡単に実現できます。
解説の中でも説明しましたが、DeleteView
では POST
リクエストを受け取った際にデータベースからのインスタンスの削除が行われます。GET
リクエスト時にはインスタンスの削除が行われないという点に注意してください。GET
リクエスト時には削除確認用のページの表示が行われます。削除するだけなのでフォームからのデータの送信は不要であり、GET
リクエスト時に削除が実行されると考えても不自然ではないのですが、実際には POST
リクエスト時にデータベースからのインスタンスの削除が行われるようになっています。
また、GET
リクエストや POST
リクエストを受け取った際には特定の1つのインスタンスのみをデータベースから取得することになり、この際の処理は DetailView
と同様になります。なので、DetailView
を使いこなせるようになっておけば、DeleteView
も簡単に使いこなすことができると思います。
ウェブアプリを運営していく上では、データベースからのインスタンス(レコード)の削除も重要な機能となりますので、是非 DeleteView
についても使いこなせるようになっておきましょう!
また、このサイトでは他の View のサブクラス
についても説明していますので、他のページも是非読んでみてください!