#内容
Djangoでログイン処理を簡潔に実装するためのクラスベースビューであるLoginView(認証用クラスベースビュー)において、HTMLへフォームを表示させるときのformの正体を教えていただいたためメモします。AuthenticatedFormを継承している他の汎用クラスベースビューでも同様だと思います。
#form が現れる例
ログイン画面の作成を想定し、以下のようなurl.pyを記述しました。
from django.urls import path
from django.contrib.auth.views import LoginView,LogoutView
urlpatterns = [
path('login/',LoginView.as_view(
redirect_authenticated_user=True,
template_name='accounts/login.html'
),name='login'),
]
このとき、Djangoが自動でログインに必要なフォームの生成を行ってくれるので利用し、login.htmlを作成します。
{% extends 'base.html' %}
{% block main %}
{% csrf_token %}
{{ form }}
<button type="submit">ログイン</button>
{% endblock %}
ここで前述のフォームはlogin.htmlの {{ form }} で受け取り、表示されています。urls.py内ではformという変数は宣言しておらず、いったいどこから現れたのかが疑問でした。
調べても欲しい情報が見当たらなかったため、terartailで有識者のご意見を伺うとすぐに以下のような回答をいただきました。
LoginViewでform_class = AuthenticationFormでformを定義しています。
コード見て継承を辿っていくと、FormViewが継承しているFormMixinのget_context_dataでget_form,get_form_classからself.form_classをコンテキストとして渡しているためだと思われます。
[Django]クラスベースビューを利用した際のフォームの受け取り方
AuthenticatedFormが継承しているFormMixinのget_context_dataというメソッドから渡される値の名前がformだから、ということのようです。
書きたかったことは全てこの回答に詰まっているので後は実際にDjangoのソースコードを示すのみとします。
class LoginView(SuccessURLAllowedHostsMixin, FormView):
"""
Display the login form and handle the login action.
"""
form_class = AuthenticationForm
class FormMixin(ContextMixin):
"""Provide a way to show and handle a form in a request."""
(中略)
def get_context_data(self, **kwargs):
"""Insert the form into the context dict."""
if "form" not in kwargs:
kwargs["form"] = self.get_form()
return super().get_context_data(**kwargs)
このget_context_dataメソッドの二行目がポイントみたいです。
kwargs["form"] = self.get_form()
確かにformという名前の値が登場しています。
#反省点
疑問点が生じ、調べてもわからなかった場合はきちんと当該ソースコードの継承を追うことも頭に入れておく必要があることがわかりました。
Qiitaを利用するのは初めてなので、改善点や問題点とうご指摘いただければ大変助かります。