FormViewの継承関係を見てみる
継承先が見れるようになったので確認してみる。 ProcessFormViewは、CreateViewや、FormViewを継承しているBaseCreateViewを継承しているクラス。 ややこしい。
getが呼び出される時、get_context_data()が動作してそれを返しているのが分かる。
FormViewはBaseFormViewとTemplateResponseMixinを継承。
class FormView(TemplateResponseMixin, BaseFormView): """A view for displaying a form and rendering a template response."""
この2つのクラスを見てみる。
class BaseFormView(FormMixin, ProcessFormView): """A base view for displaying a form."""
ProcessFormViewを見てみると、getが呼び出された時には、get_context_data()が呼び出され、コンテキストを取得した後で、render_to_response関数が走っていることが分かる。 get_context_data()はというと、FormMixinの中にある。
class ProcessFormView(View): """Render a form on GET and processes it on POST.""" Getメソッドが呼び出される。 def get(self, request, *args, **kwargs): """Handle GET requests: instantiate a blank version of the form.""" ※空のフォームで初期化している。 render_to_responseはTemplateResponseMixinのrender_to_responseを呼び出している。 return self.render_to_response(self.get_context_data()) Postメソッドが呼び出される。 def post(self, request, *args, **kwargs): """ Handle POST requests: instantiate a form instance with the passed POST variables and then check if it's valid. """ 渡されたPOST変数でフォームを初期化して、それをバリデーションチェックしている。 ※ここでformを取得している。 form = self.get_form() ※バリデーションを実施 if form.is_valid(): return self.form_valid(form) else: return self.form_invalid(form) # PUT is a valid HTTP verb for creating (with a known URL) or editing an # object, note that browsers only support POST for now. def put(self, *args, **kwargs): return self.post(*args, **kwargs)
この中でgetメソッド実行時のget_context_data()が走っている。
class FormMixin(ContextMixin): """Provide a way to show and handle a form in a request.""" initial = {} form_class = None success_url = None prefix = None def get_initial(self): """Return the initial data to use for forms on this view.""" return self.initial.copy() def get_prefix(self): """Return the prefix to use for forms.""" return self.prefix def get_form_class(self): """Return the form class to use.""" return self.form_class def get_form(self, form_class=None): """Return an instance of the form to be used in this view.""" if form_class is None: form_class = self.get_form_class() return form_class(**self.get_form_kwargs()) def get_form_kwargs(self): """Return the keyword arguments for instantiating the form.""" kwargs = { 'initial': self.get_initial(), 'prefix': self.get_prefix(), } if self.request.method in ('POST', 'PUT'): kwargs.update({ 'data': self.request.POST, 'files': self.request.FILES, }) return kwargs def get_success_url(self): """Return the URL to redirect to after processing a valid form.""" if not self.success_url: raise ImproperlyConfigured("No URL to redirect to. Provide a success_url.") return str(self.success_url) # success_url may be lazy def form_valid(self, form): """If the form is valid, redirect to the supplied URL.""" return HttpResponseRedirect(self.get_success_url()) def form_invalid(self, form): この中で指定したformに値を入れてrender_to_responseで返している。 """If the form is invalid, render the invalid form.""" return self.render_to_response(self.get_context_data(form=form)) def get_context_data(self, **kwargs): """Insert the form into the context dict.""" ※フォームを辞書型のコンテキストの中に挿入している。 if 'form' not in kwargs: kwargs['form'] = self.get_form() ※引数の値を格納している。 ※superクラスではextra_contextという変数へ格納しているだけ。 return super().get_context_data(**kwargs)
class TemplateResponseMixin: """A mixin that can be used to render a template.""" template_name = None template_engine = None response_class = TemplateResponse content_type = None def render_to_response(self, context, **response_kwargs): """ Return a response, using the `response_class` for this view, with a template rendered with the given context. Pass response_kwargs to the constructor of the response class. """ response_kwargs.setdefault('content_type', self.content_type) return self.response_class( request=self.request, template=self.get_template_names(), context=context, using=self.template_engine, **response_kwargs ) def get_template_names(self): """ Return a list of template names to be used for the request. Must return a list. May not be called if render_to_response() is overridden. """ if self.template_name is None: raise ImproperlyConfigured( "TemplateResponseMixin requires either a definition of " "'template_name' or an implementation of 'get_template_names()'") else: return [self.template_name]
class ProcessFormView(View): """Render a form on GET and processes it on POST.""" def get(self, request, *args, **kwargs): """Handle GET requests: instantiate a blank version of the form.""" return self.render_to_response(self.get_context_data()) def post(self, request, *args, **kwargs): """ Handle POST requests: instantiate a form instance with the passed POST variables and then check if it's valid. """ form = self.get_form() if form.is_valid(): return self.form_valid(form) else: return self.form_invalid(form) # PUT is a valid HTTP verb for creating (with a known URL) or editing an # object, note that browsers only support POST for now. def put(self, *args, **kwargs): return self.post(*args, **kwargs)
取り敢えず、render関連の関数とバリデーション関連の関数は別クラスになっていることが分かる。 POSTメソッドでは、バリデーションが通ったら、フォームの値をコンテキストへ詰めてrenderしているということがわかる。