このページでは、Django フレームワークで定義される CreateView
の使い方について説明していきます。
この CreateView
は View
というクラスのサブクラスの1つであり、ビューをクラスベースで作成する際に利用するクラスとなります。この View のサブクラス
を継承し、さらにクラス変数を定義したりメソッドをオーバーライドすることで、あなたが開発したいアプリに応じたビューを作成することが可能となります。
この辺りのクラスベースビューやクラスベースビューの作り方については下記ページで解説していますので、詳しくはこちらをご参照ください。
【Django入門15】クラスベースビューの基本Contents
CreateView
では、まずは CreateView
について解説していきたいと思います。
レコードの新規登録を実現するクラス
CreateView
は、名前の通り、データベースのテーブルへのレコードの新規登録を実現する View のサブクラス
となります。Django において、データベースのテーブルはモデルクラス(モデル)であり、レコードとはモデルクラスのインスタンスとなります。したがって、CreateView
は特定のモデルクラスのテーブルへのインスタンスを新規登録を実現する View のサブクラス
とも言えます。
この CreateView
は django.views.generic
から import
して利用します。
from django.views.generic import CreateView
ウェブアプリでは、データベースへのレコードの新規登録を行うものが非常に多いです。例えば、ユーザーの新規登録も、コメントの新規投稿も、レコードの新規登録によって実現されます。そして、このようなレコードの新規登録を実現するビューは、CreateView
を継承することで簡単に作成することが可能です。
スポンサーリンク
GET
と POST
の両方のメソッドに対応するクラス
こういった、レコードの新規登録を行うような場合、フォームを表示してユーザーからの必要な情報の入力を受け付け、さらに、そのフォームから送信されてきたデータに応じたレコードをテーブルに新規登録するようなビューを作る必要があります。
CreateView
においては、メソッドが GET
のリクエストを受け取った時に CreateView
の get
メソッドが実行され、その get
メソッドでフォームを表示する処理が実行されるようになっています。
また、メソッドが POST
のリクエストを受け取った時には CreateView
の post
メソッドが実行され、その post
メソッドでフォームから送信されてきたデータに応じたレコードをテーブルへ新規登録する処理が実行されるようになっています。そして、レコードの新規登録後には特定の URL へのリダイレクトレスポンスが返却されるようになっています。(フォームから送信されてきたデータが妥当でない場合には、再度フォームを表示するような処理が実行されるようにもなっています)。
CreateView
を継承するクラスを定義すれば、そのクラスには上記のようなメソッドも引き継がれることになります。なので、CreateView
を継承するクラスを定義することで、上記のような処理を別途実装することなく、データベースのテーブルへのレコードの新規登録を実現するビューが作成することができることになります。
また、上記のように、メソッドが GET
のリクエストと POST
のリクエストの両方に対応しているという点は、CreateView
の特徴の1つとなります。
例えば View のサブクラス
には下記ページで紹介している ListView
や DetailView
がありますが、これらはデータベースのレコードを表示することに特化したクラスであり、メソッドが GET
のリクエストにのみ対応しています。そのため、これらの ListView
や DetailView
は post
メソッドを持っていません。
CreateView
を継承するメリット
POST
にも対応し、post
メソッドも定義されている分、CreateView
を継承するクラスを扱うのは ListView
や DetailView
よりも難易度が若干高くなります。まぁ、でも、この辺りは関数ベースでビューを扱う場合も一緒だと思います。クラスベースでも関数ベースでも結局 POST
に対応する分の労力が必要になります。
ですが、POST
への対応に関して言えば、関数ベースビューよりもクラスベースビューの方が確実に楽に実現できると思います。関数ベースビューの場合は、関数の中でメソッドが GET
であるか POST
であるかを判断し、その判断結果に基づいて処理を切り変えるような実装を開発者自身が行う必要があります。
この辺りは、下記のフォームの解説ページで説明していますので、詳しく知りたい方は下記ページをご参照いただければと思います。
【Django入門5】フォームの基本それに対し、クラスベースビューの場合、メソッドが GET
であるか POST
であるかの判断を行い、それに応じて実行する処理を切り替えるような実装が View のサブクラス
で既に行われています。そして、その View のサブクラス
の例の1つが、今回扱う CreateView
となります。したがって、開発者は、関数ベースビューでは必要だったメソッドに応じた処理の切り替えの実装が不要となります。
つまり、次の CreateView でのクラスベースビューの作り方 で説明する手順で CreateView
を継承するクラスを定義しておけば、あとはリクエストを受け取った際にリクエストに応じた処理が自動的に実行されるようになっています。そのため、CreateView
を継承してクラスベースビューを作成することで処理の実装量を減らすことができますし、メソッドに応じた分岐処理等の実装も不要となるためバグも発生しにくくなります。
CreateView
でのクラスベースビューの作り方
では、次はその CreateView
でクラスベースビューを作成する手順について説明していきたいと思います。
CreateView
でのクラスベースビューの作り方は、大まかに言えば ListView
や DetailView
等の他の View のサブクラス
の時と同様です。
つまり、views.py
に CreateView
を継承するクラスを定義し、そのクラスでクラス変数やメソッドを定義して CreateView
側で定義されているクラス変数の上書き・メソッドのオーバーライドを行なうことで、ビューを作成していきます。これにより、CreateView
の特徴を活かしながら自身のウェブアプリに応じたビューにカスタマイズしていくことが可能となります。
もう少し具体的に言えば、前述の通り、CreateView
ではリクエストに応じて get
メソッドや post
メソッドが実行されるようになっており、CreateView
のクラス変数や他のメソッドは、これらの get
メソッドおよび post
メソッドから利用されるようになっています。したがって、CreateView
を継承するクラス側でクラス変数やメソッドを上書き・オーバーライドしてやれば、この get
メソッドと post
メソッドの動作を変化させることができます。
これらの get
メソッドや post
メソッドの動作を変化させ、開発するウェブアプリに適したビューに仕立てるために、CreateView
を継承するクラスでのクラス変数やメソッドの定義が必要となります。
スポンサーリンク
利用するフォームを設定する
この CreateView
でクラスベースビューを作成する場合にポイントになるのがクラス変数の定義によるフォームクラスの設定になります。
CreateView
にはフォームが必要
まず、インスタンスの新規登録を実現するためには、get
メソッドが実行された際に新規登録するインスタンス(レコード)の情報の入力・送信を受け付けるためのフォームを表示する必要があります。そして、このフォームはフォームクラスのインスタンスを HTML に要素として埋め込むことで表示されるようになっており、そのインスタンスのクラスを CreateView
を継承するクラス側で設定しておく必要があります。
また、post
メソッド実行時にもフォームクラスのインスタンスが必要となります。そのため、そのインスタンスの基になるフォームクラスを CreateView
を継承するクラス側で設定しておく必要があります。
具体的にいうと、post
メソッド実行時はフォームから送信されてきたデータを受け取り、そのデータからフォームクラスのインスタンスが生成されます。そして、このインスタンスに is_valid
メソッドを実行させることで、送信されてきたデータの妥当性の検証が行われます。さらに、妥当性の検証結果が OK の場合は、そのインスタンスに save
メソッドを実行させることで、送信されてきたデータがレコードとしてデータベースへ新規登録されることになります。
CreateView
が利用するフォームは『モデルフォーム』
ここでポイントになるのがフォームクラスのインスタンスの save
メソッドが実行されるという点になります。通常のフォームクラスには save
メソッドが存在しないため、CreateView
を継承するクラスで利用するのは単なるフォームクラスではなくモデルフォームクラスである必要があることになります。下記ページでも解説しているとおり、モデルフォームクラスは model
に指定したモデルクラスに基づいて生成されるクラスであり、このクラスのインスタンスに save
メソッドを実行させれば、その model
に指定したモデルクラスのテーブルにレコード保存されることになります。
ここで覚えておいていただきたいのは、データベースへの新規登録を行うためには、新規登録先のテーブルを指定する必要があり、それを決めるのがモデルフォームクラスになるという点になります。
post
メソッド実行時の動作の説明に戻ると、post
メソッドから妥当性の検証が行われて検証結果が NG の場合は、フォームクラスのインスタンスを再度 HTML に埋め込んだものをレスポンスとしてクライアントに返却することで、クライアント側で再度フォームの表示及び入力の再受付が行われるようになっています。
このような動作はフォームを扱う上での典型的な処理の流れとなっており、先ほども紹介した下記ページのフォームの解説ページでも詳しく説明していますので、復習したい方は是非下記ページを読んでみてください。
【Django入門5】フォームの基本このように、CreateView
および CreateView
のサブクラスでは多くの場面でフォームクラスが利用されることになり、CreateView
のサブクラスを定義する際にはフォームクラスの設定が非常に重要となります。
CreateView
が利用するフォームは form_class
で指定可能
そして、CreateView
のサブクラスで利用するフォームクラスは、下記のクラス変数を定義することで設定することができます。
- クラス変数
form_class
を定義する - クラス変数
model
とfields
を定義する
前者に関しては分かりやすくて、クラス変数 form_class
を定義して CreateView
のサブクラスで利用するフォームクラスを直接指定する実現方法になります。クラス変数 form_class
を定義することで、form_class
に指定したフォームクラスが CreateView
のサブクラスから利用されるようになり、そのクラスのインスタンスがフォーム要素としてページに表示されたりデータベースへの保存を行なったりするようになります。
前述の通り、form_class
にはモデルフォームクラスを指定する必要があります。モデルフォームクラスに関しては下記ページで解説していますので、モデルフォームクラスをご存知ない方は下記ページを参照してください。要は、モデルクラスに基づいて自動的に生成されるフォームクラスがモデルフォームクラスとなります。
CreateView
が利用するフォームは model
& fields
で指定可能
後者に関しては、CreateView
の中で model
で指定されたモデルクラスと fields
で指定されたフィールドに基づいて新たにモデルフォームクラスを生成させ、そのフォームクラスを利用するように設定する実現方法になります。
model
には新規登録したいインスタンス(レコード)のモデルクラスを指定し、fields
にはフォームで扱いたいフィールドをリスト形式やタプル形式で指定します。この fields
に指定するリストやタプルの要素は model
に指定したモデルクラスの持つフィールドである必要があります。このようにクラス変数を定義することで、CreateView
の get
メソッドや post
メソッドが実行される際には、fields
に指定したリストやタプルに含まれるフィールドのみを持つモデルフォームクラスが生成されることになります。そして、それを利用して get
メソッドや post
メソッドが動作することになります。
前者と後者のどちらの方法を採用しても CreateView
のサブクラスはうまく動作させられることになりますが、モデルフォームクラスを定義しているのであれば前者の方法を、それ以外は後者の方法を採用するので良いと思います。
いずれにしても、この利用するフォームを設定する必要がある点は CreateView
のサブクラスを使いこなす上で重要となりますので、是非この点は覚えておいてください。
リダイレクト先の URL を設定する
また、CreateView
でクラスベースビューを作成する上ではリダイレクト先の URL の設定も必要となります。
CreateView
ではフォームから送信されてきたデータに対して妥当性の検証が行われ、検証結果が OK の場合には送信されてきたデータがレコード(インスタンス)としてデータベースに保存されることになります。そして、保存完了後は他の URL へのリダイレクトが行われることになります。で、この時に、どの URL にリダイレクトするのかをクラス変数として定義しておく必要があります。もしくは、リダイレクト先の URL を返却するようなメソッドを定義しておく必要があります。これらが定義されていない場合は、下記のような例外が発生することになります。
No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.
このような例外の発生は下記の3つの方法により回避することができます。
CreateView
のサブクラスにクラス変数success_url
を定義するCreateView
のサブクラスにメソッドget_success_url
を定義するCreateView
のサブクラスのmodel
等で指定したモデルクラスにメソッドget_absolute_url
を定義する
リダイレクト先の URL が静的に決まるのであれば、1つ目の方法(クラス変数を定義する方法)でリダイレクト先の URL を指定するようにしてやれば良いです。リダイレクト先の URL が静的に決まらないのであれば、つまり状況やタイミング等に応じてリダイレクト先の URL を動的に決めたいのであれば、2つ目 or 3つ目の方法(メソッドを定義する方法)でリダイレクト先の URL を取得できるようにする必要があります。
例えば、ユーザーの新規登録後に、そのユーザーのマイページにリダイレクトさせたいのであれば、新規登録されるユーザーのマイページの URL が新規登録されたユーザーに応じて変化することになるため、後者の方法でリダイレクト先の URL を取得できるようにする必要があります。
ですが、ユーザーの新規登録後にユーザー一覧の表示ページにリダイレクトさせたいのであれば、ユーザー一覧の表示ページの URL は常に同じはずなので、前者の方法でリダイレクト先の URL を指定してやれば良いです。
CreateView
でクラスベースビューを作成する上では、インスタンス(レコード)の保存後にリダイレクトが行われることと、そのリダイレクト先の URL が指定できるようにクラス変数やメソッドの定義が必要であることは覚えておいてください。
妥当性の検証結果が OK の場合の処理を変更する
また、CreateView
のサブクラスでは、フォームから送信されてきたデータの妥当性の検証結果が OK の場合に実行する処理をメソッドのオーバーライドによって変更可能であることも覚えておくと良いと思います。
CreateView
では、フォームから送信されてきたデータの妥当性の検証結果が OK の場合に form_valid
というメソッドが実行されるようになっています。この form_valid
では、送信されてきたデータのレコードとしてのデータベースへの保存と前述のリダイレクトが行われるようになっています。逆に言えば、これらしか行われないようになっています。
ですが、このメソッドを CreateView
のサブクラスに定義することでオーバーライドすることができ、妥当性の検証結果が OK の場合に実行する処理を追加したり変更したりすることが可能となります。
例えば、ログイン機能を備えたウェブアプリの場合、ユーザー登録後(ユーザーのインスタンスのデータベースへの新規登録後)にログイン処理も合わせて行いたいようなことがあります。このログイン処理の追加も、CreateView
のサブクラスで form_valid
をオーバーライドし、その form_valid
の中でログイン処理を実行するようにすることで実現可能となります。
同様に、妥当性の検証結果が NG の場合には form_invalid
が実行されるようになっているため、妥当性の検証結果が NG の場合の処理の追加や変更に関しても form_invalid
のオーバーライドにより実現することができます。
とりあえず、CreateView
でクラスベースビューを作成するのであれば、『利用するフォームクラスの設定方法』、『リダイレクト先の設定方法』、『妥当性の検証結果が OK の場合に実行する処理の変更方法』に関しては覚えておいた方が良いと思います。逆に、この辺りさえしっかり理解しておけば、CreateView
でのクラスベースビューの作成には困らないと思います。
ただ、上記で紹介したクラス変数やメソッド以外のものも CreateView
で定義されており、それらを CreateView
を継承するクラスで定義することで、より細かなビューの設定を行うことも可能です。
ここからは、それらの CreateView
で定義されているクラス変数やメソッドの詳細の紹介を行っていきたいと思います。
スポンサーリンク
CreateView
のクラス変数
では、次は CreateView
で定義されているクラス変数の紹介を行なっていきます。これらのクラス変数を CreateView
を継承するクラスで定義し直して上書きすることでクラスの動作のカスタマイズを行うことが可能となります。
CreateView
の場合、GET
メソッドのリクエストを受け取った際に get
メソッドが実行され、GET
メソッドのリクエストを受け取った際に post
メソッドが実行されることになるため、これらの get
メソッドや post
メソッドの動作を変化させることを目的にクラス変数の定義を行なっていくことになります。
CreateView
のクラス変数の一覧
その CreateView
で定義されるクラス変数には下記のようなものが存在します。
- form_class
- success_url
- model
- fields
- initial
- prefix
- template_name
- template_name_suffix
- extra_context
- template_engine
- response_class
- content_type
extra_context・template_engine・response_class・content_type に関しては ListView
のクラス変数の役割と全く同じなので、詳しくは ListView
の解説ページを参照していただければと思います(これら4つの各リンクには ListView
の解説ページでの説明部分へのリンクを設定しています)。
また、これらが CreateView
で定義されているクラス変数の全てというわけではないので注意してください。定義はされているものの CreateView
では基本的に使用しないクラス変数は省き、さらにカスタマイズに利用する機会の多そうなもののみを紹介しています。全てのクラス変数を知りたい場合は、実際に CreateView
の定義をソースコードで確認していただくのが一番早いと思います。
また、ここからは、アプリの models.py
で下記のような Comment
が定義されていることを、前提に解説を行なっていきます。
from django.db import models
class Comment(models.Model):
text = models.CharField(max_length=256)
date = models.DateField(auto_now_add=True)
slug = models.SlugField(max_length=256, null=True, unique=True)
さらに、アプリの forms.py
で下記のような CreateCommentForm
が定義されていることを、前提に解説を行なっていきます。
from django import forms
from .models import Comment
class CreateCommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text', 'slug']
slug
フィールドの役割や意味合いについては下記の DetailView
の解説ページの中で説明していますので、必要に応じて下記ページを参照していただければと思います。
では、先ほど挙げたクラス変数の役割や、これらを定義することで実現できることについて、1つ1つ説明していきます。
form_class
最初に紹介するクラス変数が form_class
で、CreateView
でクラスベースビューを作成していく上で一番のポイントになるのが、この form_class
になると思います。
この form_class
はビューで扱うフォームクラスを指定するクラス変数になります。利用するフォームを設定する でも説明したように、form_class
には単なるフォームクラスではなくモデルフォームクラスを指定します。
また、form_class
で指定したフォームクラスは、これも 利用するフォームを設定する で説明したように、フォームを表示する際やフォームから送信されてきたデータをインスタンスとしてデータベースに保存するときなど、様々な場面で利用されることになります。
例えば、下記のように CommentCreate
を定義すれば、CommentCreate
の get
メソッドや post
メソッド実行時に CreateCommentForm
が利用されるようになります。
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
form_class = CreateCommentForm
CreateView
のサブクラスにおいては、この form_class
、もしくは、後述で紹介する model
& fields
の定義が必須となります。
スポンサーリンク
success_url
前述の通り、CreateView
は post
メソッドを持っており、post
メソッド実行時にはフォームから送信されてきたデータのレコード(インスタンス)としてのデータベースへの保存が行われ、その後に特定の URL にリダイレクトをするようになっています(リダイレクトのレスポンスを返却する)。
success_url
は、この時のリダイレクト先の URL を指定するためのクラス変数となります。
例えば、下記のように CommentCreate
を定義すれば、CommentCreate
の post
メソッドが実行されてデータベースへのインスタンスの保存が行われた後に 'comments'
という名前が付けられた URL にリダイレクトされるようになります。
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
from django.urls import reverse_lazy
class CommentCreate(CreateView):
form_class = CreateCommentForm
success_url = reverse_lazy('comments')
ウェブアプリがリクエストを受け付ける URL に対しては urls.py
によって名前をつけることができます。そして、その名前から URL に変換するのが、上記で利用している reverse_lazy
となります。
reverse_lazy
については下記ページで解説していますので、詳しくは下記ページをご参照ください。success_url
に URL を指定する際には reverse
ではなく reverse_lazy
を利用する必要がある点がポイントとなります。
また、クラス変数 success_url
に指定できるのは静的な URL のみとなります。状況に応じてリダイレクト先の URL を動的に変化させたいような場合は get_success_url
メソッドのオーバーライドを行う or モデルクラスに get_absolute_url
を定義する必要があります。この詳細については、後述の get_success_url で説明します。
model
また、利用するフォームを設定する で説明したように、クラス変数 form_class
を定義するのではなく、ここで説明する model
と次に説明する fields
をクラス変数として定義することでも CreateView
のサブクラスが利用するフォームを設定することが可能です。
クラス変数 form_class
を指定した場合は、form_class
で指定されたクラスがフォームとして利用されることになります。それに対し、model
と fields
を指定した場合は、これらにセットされたモデルクラスとフィールドからフォームクラスオブジェクトが生成され、それがフォームとして利用されることになります。
ListView
や DetailView
ではインスタンスの取得先のテーブルを指定するために model
を定義しましたが、CreateView
の場合はインスタンスの取得先のテーブルを指定するのではなく、form_class
が定義されていない場合に利用するフォームを生成するために定義することになります。また、後述でも説明しますが、クラス変数 template_name
を定義しない場合も、この model
の定義が必要になります。
逆に言えば、form_class
と template_name
の両方が定義されているのであれば、model
の定義はあってもなくても良いです。
詳細な説明は省略しますが、model
の代わりに queryset
を定義することも可能です
クエリには操作対象となるテーブル(モデルクラス)の情報が含まれており、その情報から特定したモデルクラスが model
の代わり利用されることになります
例えば、Comment
の持つフィールドに応じたフォームを CreateView
を継承するクラスから利用するようにしたいのであれば、下記のように model
を定義してやれば良いことになります。
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
model = Comment
ただし、単に上記のように model
を定義しただけだと次のような例外が発生することになります。
Using ModelFormMixin (base class of CommentCreate) without the 'fields' attribute is prohibited.
この例外のメッセージからも分かるように、クラス変数 model
だけでなくクラス変数 fields
も一緒に定義してやれば、この例外は解決することができます。
つまり、CreateView
のサブクラスにおいて、扱うフォームをクラス変数 form_class
ではなくクラス変数 model
で設定する場合はクラス変数 fields
の定義が必須となります。
fields
では、続いては、その fields
について説明していきます。
fields
は、フォームに表示するフィールドを指定するクラス変数となります。違う言い方をすれば、ユーザーからの値の入力の受付を行うフィールドを指定するクラス変数となります。model
に指定するのはモデルクラスで、このモデルクラスはデータベースのテーブルにあたり、このテーブルは models.py
でのモデルクラスの定義に基づいてフィールド(カラム)を持つことになります。
fields
は、このテーブルのフィールドの中のどれをフォームのフィールドとして扱うのかを指定するクラス変数となります。
そして、model
と fields
を定義しておけば、利用するフォームを設定する で説明したように、これらによって指定されたフィールドの入力受付を行うフォーム(モデルフォームクラス)が定義され、そのフォームが CreateView
のサブクラスで扱われるようになります。
例えば下記のように CommentCreate
を定義すれば、Comment
の text
とslug
をフィールドとして持つモデルフォームクラスが生成され、それを CommentCreate
が利用するようになります。
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
model = Comment
fields = ['text', 'slug']
したがって、CommentCreate
でフォームを表示する際には、下の図のように text
と slug
の入力受付を行うフォームが表示されるようになります。
このフォームの表示を行うためにはテンプレートファイルの用意であったり、利用するテンプレートファイルを指定するクラス変数の定義が必要となります。この辺りは後述で解説していきます。
前述の通り、model
と fields
はセットで定義する必要があります。逆に、form_class
を定義する場合には fields
の定義は禁止されており form_class
と fields
の両方をクラス変数として定義すると下記のような例外が発生することになるので注意してください。この場合は fields
の定義を削除してやれば例外を解消することができます。
Specifying both 'fields' and 'form_class' is not permitted.
スポンサーリンク
initial
initial
はフォームの各種フィールドの初期値を指定するクラス変数となります。このクラス変数 initial
には、下記のように辞書形式のデータを指定する必要があります。
initial = {
'フィールド1のフィールド名': フィールド1の初期値,
'フィールド2のフィールド名'; フィールド2の初期値
}
クラス変数 initial
でフォームの各種フィールドに初期値を指定しておけば、フォームが表示された際に、各種フィールドに初期値に指定した値が表示されるようになります。
例えば下記のように CreateView
を定義すれば、クラス変数 initial
により、GET
メソッドのリクエストによってフォームが表示される際に text
フィールドには hello
という文字列が入力された状態で表示されることになります。それに対し slug
フィールドには初期値を指定していないため、slug
フィールドは空白の状態で表示されることになります。
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
model = Comment
fields = ['text', 'slug']
initial = {
'text': 'hello'
}
実際のフォームの表示結果は下記のようなものになります。
prefix
prefix
は各種フィールドのタグの属性に指定する文字列に接頭辞を付加するためのクラス変数となります。
例えば、先ほどの initial の説明の中で示した CommentCreate
の例の場合、生成される HTML において、フォームの中の text
フィールドと slug
フィールドのタグは下記のようなものになります。
<tr>
<th><label for="id_text">Text:</label></th>
<td>
<input type="text" name="text" value="hello" maxlength="256" required id="id_text">
</td>
</tr>
<tr>
<th><label for="id_slug">Slug:</label></th>
<td>
<input type="text" name="slug" maxlength="256" required id="id_slug">
</td>
</tr>
それに対し、下記のようにクラス変数 prefix
を定義した場合、
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
model = Comment
fields = ['text', 'slug']
initial = {
'text': 'hello'
}
prefix = 'comment'
生成される HTML において、フォームの中の text
フィールドと slug
フィールドのタグは下記のようなものに変化します。ところどころ、属性に指定される文字列に prefix
に指定した comment
が付加されていることが確認できると思います。一部接頭辞ではないものもありますが…。まぁとりあえず、こんな感じで各属性への指定値に特定の文字列を追加で付加するためのクラス変数が prefix
となります。
<tr>
<th><label for="id_comment-text">Text:</label></th>
<td>
<input type="text" name="comment-text" value="hello" maxlength="256" required id="id_comment-text">
</td>
</tr>
<tr>
<th><label for="id_comment-slug">Slug:</label></th>
<td>
<input type="text" name="comment-slug" maxlength="256" required id="id_comment-slug">
</td>
</tr>
template_name
ここからは、テンプレートファイルに関するクラス変数について説明していきます。CreateView
の場合、GET
メソッドのリクエストを受け取ってフォームを表示する際にテンプレートファイルが利用されます。
また、POST
メソッドのリクエストを受け取った場合でも、フォームから送信されてきたデータの妥当性の検証の検証結果が NG の場合には再度フォームを表示することになるため、その際にもテンプレートファイルが利用されることになります。
こういったページの表示を行う際に利用するテンプレートファイルのパスを指定するのがクラス変数 template_name
となります。このパスには、アプリの templates
フォルダから見た相対パスを指定します。
デフォルトでは、テンプレートファイルのパスとして アプリ名/モデルクラス名_form.html
が設定されるようになっているため、CreateView
を継承するクラスが動作する際は、あらかじめこのパスにテンプレートファイルを用意しておくか、template_name
を定義して template_name
に指定したパスにテンプレートファイルを用意しておく必要があります。
例えば、forum
というアプリの views.py
で下記のように CommentCreate
を定義した場合、テンプレートファイルは forum/templates/forum/create.html
に用意しておく必要があります。
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
form_class = CreateCommentForm
template_name = 'forum/create.html'
また、これに関しては後述の CreateView が生成するコンテキスト で説明しますが、CreateView
が生成するコンテキストには form
キーに form_class
で指定したフォームクラスのインスタンス or model
+ fields
から生成されるクラスのインスタンスがセットされることになるため、用意するテンプレートファイルでは form
変数をフォームとして出力するようにしておく必要があります。
template_name
を指定しない場合は、クラス変数 model
の定義が必須となるという点に注意してください。template_name
を指定しない場合は、前述のとおり アプリ名/モデルクラス名_form.html
がテンプレートファイルのパスとなるのですが、この モデルクラス名
部分は、クラス変数 model
に指定したモデルクラスのクラス名を小文字に変換したものとなります。したがって、クラス変数 template_name
とクラス変数 model
の両方を定義していない場合、テンプレートファイルのパスが定まらなくなり、下記のような例外が発生することになります。
TemplateResponseMixin requires either a definition of 'template_name' or an implementation of 'get_template_names()'
このような例外が発生したら、クラス変数 model
or クラス変数 template_name
を定義して例外を解消するようにしてください。
スポンサーリンク
template_name_suffix
先ほど template_name
を定義しなかった場合、テンプレートファイルのパスとして アプリ名/モデルクラス名_form.html
がデフォルトで設定されると言いましたが、この _form
部分はクラス変数 template_name_suffix
を定義して変更することも可能です。
template_name_suffix
は、その名の通りデフォルトのテンプレートファイルのパスにおけるファイル名の末尾を指定するクラス変数であり、CreateView
の場合はデフォルトで '_form'
が指定されています。
例えば、forum
というアプリの views.py
で下記のように CommentCreate
を定義した場合、
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
model = Comment
fields = ['text', 'slug']
template_name
を指定していないため、デフォルト設定のテンプレートファイルが利用されることになり、そのファイルのパスは forum/comment_form.html
となりますので、このパスにテンプレートファイルを用意しておく必要があることになります。
それに対し、下記のように CommentCreate
を定義した場合、
from django.views.generic import CreateView
from .models import Comment
from .forms import CreateCommentForm
class CommentCreate(CreateView):
model = Comment
fields = ['text', 'slug']
template_name_suffix = '_create'
デフォルト設定のテンプレートファイルが利用されるという点は先ほどと同じですが、template_name_suffix
に '_create'
を指定しているため、利用されるテンプレートファイルのパスは forum/comment_create.html
となります。
CreateView
のメソッド
次に CreateView
の持つメソッドを紹介していきます。CreateView
を継承したクラスを定義し、そのクラスで CreateView
の持つメソッドをオーバーライドしてやることで CreateView
とは異なる動作のクラスを実現することができるようになります。
まずはメソッド一覧を示し、続いて、その中からオーバーライドする機会が多そうなメソッドのみの詳細を説明するようにしたいと思います。
CreateView
のメソッド一覧
CreateView
の持つメソッドの一覧は下記のようになります。あくまでもクラスのカスタマイズ目的でオーバーライドを行う可能性のあるものを挙げており、as_view
などのカスタマイズは行わないであろうメソッドは省略しています。
また、CreateView
は 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
メソッドの処理の流れ
get
メソッドと post
メソッドの処理について簡単に説明しておくと、まず get
では get_context_data
メソッドが呼び出され、このメソッドの中でフォームクラスのインスタンスが生成され、それがコンテキストの 'form'
キーに値としてセットされることになります。さらに、このフォームクラスのインスタンスの生成は、get_context_data
メソッドから呼び出しされる get_form
メソッドで実施されるようになっています。
そして、この get_form
メソッドからは最初に get_form_class
が呼び出され、クラス変数 form_class
で指定されたクラス or model
+ fields
によって生成されるクラスが取得されます。さらに、get_form_kwargs
で、それらのクラスのコンストラクタに指定するキーワード引数が取得されます。この中でクラス変数 initial
やクラス変数 prefix
が取得され、それがキーワード引数に指定された状態でコンストラクタが実行されることで、これらのクラス変数への指定値が反映された状態のフォームクラスのインスタンスが生成されることになります。
そして、前述のとおり、このフォームクラスのインスタンスがコンテキストの 'form'
キーに値としてセットされます。コンテキスト生成後には render_to_response
メソッドが実行され、コンテキストとテンプレートファイルに基づいて HTML が生成されてレスポンスとして返却されることになります。
ちなみに、下記ページで紹介している “インスタンスの更新を行う View のサブクラス
” である UpdateView
においては、前述の get_form_kwargs
で事前にデータベースから取得した更新対象のインスタンスが 'instance'
キーにセットされた辞書が取得されるようになっています。そして、それを引数としてコンストラクタが実行されてフォームクラスのインスタンスが生成されることになります。
したがって、UpdateView
では get
メソッド実行時に事前に取得されたインスタンスの情報が各種フィールドにセットされた状態でフォームが表示されることになりますし、後述の post
メソッド実行時には事前に取得されたインスタンスをフォームから送信されてきたデータで上書きしたものがデータベースに保存されるようになっています。
こういった違いはあるものの、基本的には、UpdateView
と CreateView
では事前にインスタンスをデータベースから取得するかどうかと、get_form_kwargs
が返却する辞書に事前に取得したインスタンスがセットされているかどうかの違いしかありません。そのため、CreateView
をしっかり理解しておけば UpdateView
も簡単に使いこなすことができます!
post
メソッドの処理の流れ
また、post
メソッドでは、まず get_form
メソッドが実行されてフォームのインスタンスの生成が行われます。このフォームのインスタンスがコンストラクタで生成される際にはコンストラクタの引数にフォームから送信されてきたデータが指定されることになるため、各種フィールドにフォームから送信されてきたデータがセットされた状態のインスタンスが生成されることになります。
さらに、生成されたインスタンスに is_valid
メソッドを実行させることで、送信されてきたデータの妥当性の検証が行われます。この is_valid
メソッドはモデルフォームクラスの持つメソッドになります。
妥当性の検証結果が OK の場合は form_valid
メソッドが実行されます。form_valid
メソッドでは、まずモデルフォームクラスのインスタンスから save
メソッドが実行され、送信されてきたデータがレコードとしてデータベースに保存されることになります。そして、get_success_url
メソッドが返却する URL に対するリダイレクトレスポンスが生成されて返却されることになります。get_success_url
メソッドではクラス変数 success_url
が定義されている場合はそれが返却され、それ以外の場合は、保存されたレコード(インスタンス)から get_absolute_method
が実行されるようになっており、このメソッドの返却値がリダイレクト先の URL として返却されることになります。
妥当性の検証結果が NG の場合は form_invalid
メソッドが実行され、この場合は get
メソッドの時と同様に HTML が生成されてレスポンスとして返却されることになります。ただし、コンテキストの 'form'
キーに値としてセットされるフォームクラスのインスタンスには、フォームから送信されてきた各種フィールドのデータおよび妥当性の検証結果が NG となった理由を示すエラーメッセージがセットされた状態となっているため、このインスタンスをフォームとして表示した際には、各種フィールドにユーザーが前回入力したデータがセットされた状態で、さらにはエラーメッセージを含む状態でフォームが表示されることになります。
この辺りの妥当性の検証であったり、妥当性の検証結果が NG となった場合のフォームの際表示に関しては下記ページで詳しく説明していますので、必要に応じて参照していただければと思います。
【Django入門5】フォームの基本簡単に説明させていただきましたが、get
メソッドや post
メソッドでは上記のような流れで処理が行われており、その中で様々なメソッドの実行やクラス変数の参照が行われるようになっています。
これらのメソッドの中で、特にオーバーライドする機会が多くなるのは form_valid
と get_success_url
になると思います。この2つについて詳細を説明していきたいと思います。
スポンサーリンク
form_valid
まず form_valid
について説明していきます。
この form_valid
に関しては 妥当性の検証結果が OK の場合の処理を変更する で説明した通りで、フォームから送信されてきたデータの妥当性の検証結果が OK である場合に実行されるメソッドになります。そして、このメソッド内部ではフォームから送信されてきたデータをレコードとしてテーブルに保存し(新規登録)、さらに特定の URL にリダイレクトするためのレスポンスを返却する処理が行われるようになっています。そのため、これ以外の処理を form_valid
で実施するようにしたいのであれば、form_valid
のオーバーライドが必要になります。
例えば下記は、【Django入門14】クラスベースビューの基本 の 掲示板アプリのビューをクラスベースに変更する で紹介した form_valid
のオーバーライドの例になります。下記の通り、form_valid
は第1引数を self
、第2引数を form
として定義する必要があります。
下記のように form_valid
を定義してオーバーライドしてやれば、スーパークラスの form_valid
、つまり CreateView
の form_valid
が実行されてテーブルへのレコードの新規登録とリダイレクトのレスポンスの生成が行われた後に login
が実行され、ここでログイン処理が行われることになります。
class Register(CreateView):
model = User
form_class = RegisterForm
template_name = 'forum/register.html'
def form_valid(self, form):
response = super().form_valid(form)
user = self.object
login(self.request, user)
return response
レコードの新規登録の後に追加で処理を行いたいことも多いので、そういったことが form_valid
のオーバーライドによって実現可能であることは是非覚えておいてください。
ただし、form_valid
は基本的にリダイレクトのレスポンスを返却する必要があるという点には注意してください。CreateView
の form_valid
の返却値もリダイレクトのレスポンスとなりますので、基本的には、その返却値をオーバーライドした側の form_valid
でも返却するようにしてやれば良いです。上記においては return response
の部分がそれにあたります。
また、フォームから送信されてきたデータの妥当性の検証結果が NG の場合は form_invalid
メソッドが実行されるようになっているため、この場合の動作を変更したい場合は、ここで紹介した form_valid
と同様に form_invalid
のオーバーライドを行うようにしましょう。
get_success_url
次は get_success_url
のオーバーライドの例を紹介していきます。
get_success_url
はリダイレクト先の URL を取得するメソッドで、このメソッドは先ほど説明した form_valid
から呼び出されるようになっています。
この get_success_url
は、クラス変数 success_url
が定義されている場合は、その success_url
に指定されている URL が返却されるようになっています。クラス変数 success_url
が定義されていない場合は、インスタンスの保存先となるモデルクラス(テーブル)の get_absolute_url
メソッドの返却値が返却されることになるのですが、この get_absolute_url
メソッドがモデルクラスに定義されていない場合は下記の例外が発生することになります。なので get_success_url
メソッドをそのまま利用する場合は、クラス変数 success_url
を定義する or モデルクラス側で get_absolute_url
メソッドを定義することが必須となります。
No URL to redirect to. Either provide a url or define a get_absolute_url method on the Model.
リダイレクト先の URL を設定する でも解説した通り、静的に決まる URL であれば、クラス変数を定義し、動的に決める必要のある URL であれば、メソッドを定義するので良いと思います。モデルクラス側に get_absolute_url
を定義して動的にリダイレクト先の URL 返却する例に関しては、後述の CreateView の利用例 で紹介します。
もしくは、get_success_url
メソッドをオーバーライドしてしまって上記のような作りから根本的に変更してしまうという手もあります。
例えば下記は、【Django入門14】クラスベースビューの基本 の 掲示板アプリのビューをクラスベースに変更する で紹介した get_success_url
のオーバーライドの例になります。
下記のように get_success_url
を定義してオーバーライドしてやれば、post
メソッドからは CreateView
の get_success_url
ではなく、Register
の get_success_url
が呼び出されるようになります。
class Register(CreateView):
model = User
form_class = RegisterForm
template_name = 'forum/register.html'
def get_success_url(self):
return reverse('user', kwargs={'user_id':self.object.pk})
この get_success_url
メソッドでは、クラス変数 success_url
も参照していませんし、get_absolute_url
メソッドも呼び出していないため、両方が定義されていなくても例外が発生しません。また、get_success_url
メソッドでは、self.object
から事前にテーブルに新規登録されたインスタンスを取得することができます。なので、get_success_url
メソッドの中で self.object
を参照することで、テーブルに新規登録されたインスタンスに応じて動的に生成した URL を返却するようなことが可能となります。
ちなみに、上記の get_success_url
では、urls.py
で 'user'
と名付けられた URL の後ろに self.object.pk
(新規登録されたインスタンスのプライマリーキー) が追加された URL が返却されることになります。
CreateView
を継承するクラスを利用する上では、レコードの新規登録後のリダイレクト先の URL も重要であり、この URL の決め方には下記の3つが存在することは覚えておきましょう!
CreateView
のサブクラスにクラス変数success_url
を定義するCreateView
のサブクラスにメソッドget_success_url
を定義するCreateView
のサブクラスのmodel
等で指定したモデルクラスにメソッドget_absolute_url
を定義する
CreateView
が生成するコンテキスト
続いて CreateView
が生成するコンテキストについて説明しておきます。
CreateView
では、コンテキストは GET
メソッドのリクエストを受け取って get
メソッドが実行された時、もしくは、POST
メソッドのリクエストを受け取って post
メソッドが実行されたけど妥当性の検証結果が NG であった時に生成されます(フォームを再表示するため)。
そして、CreateView
が生成するコンテキストには下記の要素が含まれます。見ての通り、基本的に CreateView
が生成するコンテキストは 'form'
キーのみを持つことになります。
'form'
: フォームクラスのインスタンス
このようなコンテキストを利用したテンプレートファイルからのフォームの表示の仕方の詳細については下記ページの フォームの表示 の節を参照していただければと思います。
【Django入門5】フォームの基本また、他のデータをテンプレートファイルから参照したい場合は、extra_context で説明しているクラス変数 extra_context
を定義したり、get_context_data
のオーバーライドを行なったりしてコンテキストの要素を追加する必要があります。
スポンサーリンク
CreateView
の利用例
最後に、ここまでの説明のまとめとして、CreateView
を継承するクラスでのビューの作成例を示していきたいと思います。
プロジェクトとアプリの作成やモデルクラスの定義・マイグレーションの手順に関しては下記ページの ListView の利用例 と同じとなりますので、ここでは説明を省略させていただきます。ListView
の解説ページの利用例を読んでいない方は、下記ページの プロジェクトとアプリの作成 と モデルの作成とマイグレーション を読んで手順を進めていただければと思います。
フォームの定義
プロジェクトやアプリ、モデルクラスの準備が済んだ後は、モデルフォームクラスの定義を行なっていきたいと思います。CreateView
のサブクラスでクラス変数 model
と fields
の定義を行なっておけばモデルフォームクラスは必須ではないのですが、今回の例ではモデルフォームクラスを定義し、そのフォームクラスを CreateView
のサブクラスで利用するようにしていきたいと思います。
ということで、forms.py
を作成し、そこにモデルフォームクラスの定義を行なっていきたいと思います。まず、forum
フォルダの下に forms.py
というファイルを新規作成し、その forms.py
の中身を下記のように変更して保存してください。
from django import forms
from .models import Comment
class CreateCommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ['text', 'slug']
この CreateCommentForm
の model
には Comment
を定義しているため、Comment
モデルクラスに基づいたフォームクラスが定義されることになります。したがって、この CreateCommentForm
のインスタンスから save
メソッドを実行させた場合は、Comment
モデルクラスの save
メソッドが実行されて Comment
モデルクラスのインスタンスがレコードとしてデータベースに保存されることになります。そして、この CreateCommentForm
のインスタンスからの save
メソッドの実行は、次に説明する CommentCreate
(CreateView
) の form_valid
から行われるようになっています。
さらに fields = ['text', 'slug']
を指定しているため、フォームクラスのインスタンスを表示した際には、Comment
モデルクラスに定義されているフィールドのうち、text
と slug
のみの入力受付を行うフォームが表示されることになります。
こんな感じで、モデルクラスに基づいたフォームクラスがモデルフォームクラスとなります。
クラスベースビューの作成
続いて、このページの本題でもあるクラスベースビューの作成を行っていきます。今回は、ここまでの説明の通り CreateView
を継承するクラスを定義し、そのクラスをクラス変数の定義とメソッドのオーバーライドによってカスタマイズしていきます。
今回は、下記のように views.py
を変更することでクラスベースビューを作成したいと思います。
from django.views.generic import DetailView, CreateView
from .models import Comment
from .forms import CreateCommentForm
from django.urls import reverse
class CommentCreate(CreateView):
form_class = CreateCommentForm
initial = {
'text': 'hello'
}
template_name = 'forum/commentcreate.html'
def get_success_url(self):
return reverse('comment', kwargs={'comment_id':self.object.id})
class CommentDetail(DetailView):
model = Comment
pk_url_kwarg = 'comment_id'
template_name_suffix = 'info'
この views.py
においては2つのクラスを定義しており、一方は DetailView
を継承するクラスとして CommentDetail
を定義しています。このクラスは、CommentCreate
の post
メソッドが実行された際のリダイレクト先として利用するために定義しています。
DetailView
に関しては下記ページで詳細を解説していますので、詳しく知りたい方は下記ページを参照してください。
また、もう1つのクラスが、このページで解説している CreateView
を継承するクラスとなります。このクラスでは form_class
に CreateCommentForm
を指定しているため、フォームを扱う際には CreateCommentForm
が利用されることになります。
また、CreateCommentForm
の meta
属性の model
に Comment
を指定しているため、このフォームから送信されてきたデータをレコードとして保存する際には、Comment
に対応するテーブルに保存が行われることになります。こんな感じで、CreateView
を継承するクラスでは様々なクラスが連携して動作することになる点も CreateView
を理解するポイントの1つになると思います。そして、様々なクラスが連携して動作することになるため、CreateView
のカスタマイズだけでなく、フォームクラスやモデルクラスの変更によってビューの動作を変更することも可能となります。
例えば、上記の CommentCreate
では get_success_url
をオーバーライドしています。このオーバーライドによる効果は get_success_url で既に解説したつもりなので、ここでの詳細な説明は省略しますが、下記のように、Comment
クラスに get_absolute_url
を定義しておくことでも同様のことを行うことが可能です。
def get_absolute_url(self):
return reverse('comment', kwargs={'comment_id': self.id})
CreateView
の get_success_url
では、クラス変数 success_url
が定義されていない場合、事前にデータベースに保存されたインスタンスによる get_absolute_url
メソッドの実行結果が返却されるようになっています。今回の例であれば、CommentCreate
によってデータベースに保存されるインスタンスは Comment
クラスのものとなるため、Comment
の get_absolute_url
の実行結果が get_success_url
の返却値、すなわちリダイレクト先の URL として扱われることになります。そのため、get_absolute_url
で動的に URL を生成して返却するようにしておけば、get_success_url
のオーバーライドを行わなくてもリダイレクト先の URL を動的に変更することが可能となります。
スポンサーリンク
ビューと 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('comment/<int:comment_id>/', views.CommentDetail.as_view(), name='comment'),
path('create/', views.CommentCreate.as_view(), name='create'),
]
これらの urls.py
により、ルートパス指定で /forum/create/
へのリクエストがあった際に CommentCreate
の get
メソッドが実行されてフォームが表示されるようになります。そして、フォームからデータが送信されてきた際には post
メソッドが実行され、さらにはデータベースに保存されたインスタンスのプライマリーキーを comment_id
として 'comment'
の名前が付けられた URL にリダイレクトされます( つまり /forum/comment/プライマリーキー/
へリダイレクトされる)。それにより、次は CommentDetail
の get
メソッドが実行されることになり、その保存されたインスタンスの詳細情報が表示されることになります。
テンプレートの作成
次はテンプレートファイルを作成します。ソースコードの変更としては、これが最後となります。
CommentCreate
が利用するテンプレートファイル
まず、CommentCreate
ではクラス変数 template_name
を定義し、template_name
には 'forum/commentcreate.html'
を指定しているため、アプリ内の templates
フォルダから見た相対パスが 'forum/commentcreate.html'
となる位置に存在するテンプレートファイルが利用されることになります。
このパスにテンプレートファイルを用意しておく必要があるため、forum
フォルダの中にまず templates
フォルダを作成し、さらに templates
の中に forum
フォルダを作成してください。
さらに、最後に作成した forum
フォルダの中に commentcreate.html
を新規作成し、中身を下記のように変更して保存してください。
<!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>
このテンプレートファイルでは変数として form
を参照しています。で、CreateView が生成するコンテキストで説明したように、CreateView
で生成されるコンテキストには 'form'
キーとして form_class
で指定されたフォームクラスのインスタンス or model
+ fields
から生成されるフォームクラスのインスタンスがセットされることになるため、このテンプレートファイルでは form
を参照することでフォームクラスのインスタンスが扱えることになります。そして、{{ form.as_table }}
と記述しておけば、そのフォームクラスに定義されているフィールドがテーブル形式で HTML に埋め込まれることになります。そして、それがページとして表示されることで、それらの入力フィールドを含むフォームが表示されることになります。
CommentDetail
が利用するテンプレートファイル
また、CommentDetail
で利用されるテンプレートファイルに関しては下記ページで紹介していますので、これに関しては下記ページをご参照いただければと思います。
結論としては、先ほど最後に作成した forum
フォルダの下に commentinfo.html
を新規作成し、中身を下記のように変更して保存してやれば良いです。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of DetailView</title>
</head>
<body>
<main>
<h2>コメント({{ comment.id }})</h2>
<table>
<tbody>
<tr><td>ID :</td><td>{{ comment.id }}</td></tr>
<tr><td>TEXT :</td><td>{{ comment.text }}</td></tr>
<tr><td>DATE :</td><td>{{ comment.date }}</td></tr>
<tr><td>SLUG :</td><td>{{ comment.slug }}</td></tr>
</tbody>
</table>
</main>
</body>
</html>
動作確認
最後に動作確認を行なっておきましょう!
まずは、manage.py
が存在するフォルダで下記コマンドを実行します。
% python manage.py runserver
これにより、開発用ウェブサーバーが起動しますので、ウェブブラウザから作成したアプリのページを表示することが可能となります。
次に下記 URL をウェブブラウザで表示してみてください。
http://localhost:8000/forum/create/
この URL をウェブブラウザで表示すれば下図のような text
と slug
の入力フィールドを持つフォームが表示されるはずです。
ここで表示されるフォームは CreateCommentForm
で定義されるクラスのインスタンスであり、CreateCommentForm
で Meta
属性の fields
に ['text', 'slug']
を、model
に Comment
を指定しているため、Comment
の text
と slug
フィールドを入力するためのフォームが表示されることになります。
また、text
フィールドに hello
とあらかじめ入力されているのは CommentCreate
クラスのクラス変数として initial ={'text': 'hello'}
を指定しているからになります。
表示されたフォームで適当な半角英数字の文字列を text
と slug
に入力して 送信
ボタンを押せば、これらのフィールドに入力されたデータが対応するフィールドにセットされ、さらに id
(プライマリーキー) と date
(新規作成された日時) が自動的にセットされた Comment
のインスタンスがデータベースに新規登録されることになります。ただし、slug
に関してはデータベースに保存されている他の Comment
のインスタンスと重複していると妥当性の検証結果が NG になるようになっているので注意してください。
送信
ボタンを押してインスタンスがデータベースに新規登録されれば、リダイレクトが行われ、そのインスタンスの詳細ページに自動的に遷移するようになっているはずです。
このリダイレクト先の URL は CommentCreate
クラスの get_success_url
によって決定され、そのリダイレクト先の URL は下記となります。
http://localhost:8000/forum/comment/<int:comment_id>/
この <int:comment_id>
には、フォームの送信によって新規保存されたインスタンスのプライマリーキーが自動的に設定されてリダイレクトされるようになっています。
こんな感じで、CreateView
を継承するクラスを定義してクラス変数やメソッドを適切に定義してやれば、簡単にインスタンス(レコード)の新規登録を行うビューを実現することができます。モデルクラスの定義やモデルフォームクラスの定義、さらにはクラス変数やメソッドの定義を変えてみて、その時に動作がどう変わるのかを確認していけば、もっと CreateView
への理解が深まると思いますので、是非これらにも挑戦してみてください!
スポンサーリンク
まとめ
このページでは、CreateView
および CreateView
を継承したクラスベースビューの作り方について解説しました!
CreateView
はインスタンス(レコード)をデータベースに新規登録するための View のサブクラス
であり、このクラスを継承することでユーザー登録やコメントの新規投稿等を行うページを簡単に実現できます。
CreateView
のポイントの1つはフォームを扱うという点であり、そのためにフォームクラスの定義やフォームクラスに関するクラス変数の定義等が必要になります。
また、POST
メソッドのリクエストを扱うことができるという点もポイントとなります。関数ベースビューの場合はリクエストのメソッドに応じて動作を切り替えるような処理を実装する必要があって若干ややこしいですが、クラスベースビューの場合はこのあたりの処理の実装が不要となり、クラスベースビューに置き換えることで実装が簡潔になります。なので、ListView
や DetailView
等に比べてクラスベースビューに置き換えるメリットも大きいと思います。
こういったインスタンスのデータベースへの新規登録に関してもウェブアプリで実装する機会が多い機能となると思いますので、CreateView
も使いこなせるようになっておきましょう!
このサイトでは他の View のサブクラス
についても説明していますので、他のページも是非読んでみてください!