初めに
LoginViewは、ユーザー認証とログインプロセスを容易に実装するために設計されたクラスです。
全体コードはこちら
LoginViewの継承クラス
RedirectURLMixin
クラスとFormView
クラスを継承しており、ログイン成功時のリダイレクトロジックとフォームの処理をそれぞれ担当します。
LoginViewクラス
class LoginView(RedirectURLMixin, FormView):
form_class = AuthenticationForm
authentication_form = None
template_name = "registration/login.html"
redirect_authenticated_user = False
extra_context = None
@method_decorator(sensitive_post_parameters())
@method_decorator(csrf_protect)
@method_decorator(never_cache)
def dispatch(self, request, *args, **kwargs):
if self.redirect_authenticated_user and self.request.user.is_authenticated:
redirect_to = self.get_success_url()
if redirect_to == self.request.path:
raise ValueError(
"Redirection loop for authenticated user detected. Check that "
"your LOGIN_REDIRECT_URL doesn't point to a login page."
)
return HttpResponseRedirect(redirect_to)
return super().dispatch(request, *args, **kwargs)
def get_default_redirect_url(self):
if self.next_page:
return resolve_url(self.next_page)
else:
return resolve_url(settings.LOGIN_REDIRECT_URL)
def get_form_class(self):
return self.authentication_form or self.form_class
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["request"] = self.request
return kwargs
def form_valid(self, form):
auth_login(self.request, form.get_user())
return HttpResponseRedirect(self.get_success_url())
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
current_site = get_current_site(self.request)
context.update(
{
self.redirect_field_name: self.get_redirect_url(),
"site": current_site,
"site_name": current_site.name,
**(self.extra_context or {}),
}
)
return context
属性 | 説明 |
---|---|
form_class | 使用されるフォームクラス。デフォルトではAuthenticationFormが使用される。 |
authentication_form | カスタム認証フォームを指定する場合に使用する |
template_name | ログインページのテンプレート名を指定する |
redirect_authenticated_user | 認証済みユーザーがログインページにアクセスした際にリダイレクトするかどうかを制御する |
extra_context | テンプレートに追加のコンテキストを提供するために使用する |
dispatchメソッド
基底クラスであるView
クラスのメソッドをオーバーライドしています。
このメソッドはリクエストされたHTTPメソッドに対応するビューメソッドを呼び出します。
詳しい説明はこちらをご覧ください。
このメソッドでは、redirect_authenticated_user
がTrue
であり、ユーザーが既に認証されている場合にリダイレクト処理を行います。
リダイレクト先はRedirectURLMixin
のget_success_url
メソッドを使用して取得します。
get_default_redirect_urlメソッド
このメソッドは、ログインに成功した後のデフォルトのリダイレクトURLを返します。
next_page
属性が設定されている場合はそれを使用し、そうでない場合はsettings.LOGIN_REDIRECT_URL
を使用してリダイレクト先のURLを決定します。
get_form_classメソッド
このメソッドは、使用するフォームクラスを返します。
クラスにauthentication_form
属性が設定されていれば、それを使用します。そうでなければ、form_class
属性に設定されたデフォルトのフォームクラスを使用します。
get_form_kwargsメソッド
フォームに表示させるデフォルト情報の設定と、複数のフォームを区別させることができます。
ここでは親クラスの同名メソッドをオーバーライドして、request
オブジェクトを引数に加えています。
詳しくはこちらのget_form_kwargsメソッドで説明しています。
form_validメソッド
このメソッドは、フォームのバリデーションが成功した後に呼び出されます。
ユーザーをログインさせた後、get_success_url
メソッドで取得したURLにリダイレクトします。
リダイレクト後に後続の処理は実行されません。
get_context_data
このメソッドは、テンプレートに渡すコンテキストデータを構築します。
親クラスの同名メソッドを呼び出した後、リダイレクトURL、現在のサイト、サイト名などの追加情報をコンテキストに加えます。
RedirectURLMixinクラス
このミックスインは、リダイレクト先のURLを取得するための機能を提供しています。
LoginViewクラスで使用しているリダイレクト先のURLの取得は、このクラスをオーバーライドして使用しています。
class RedirectURLMixin:
next_page = None
redirect_field_name = REDIRECT_FIELD_NAME
success_url_allowed_hosts = set()
def get_success_url(self):
return self.get_redirect_url() or self.get_default_redirect_url()
def get_redirect_url(self):
"""Return the user-originating redirect URL if it's safe."""
redirect_to = self.request.POST.get(
self.redirect_field_name, self.request.GET.get(self.redirect_field_name)
)
url_is_safe = url_has_allowed_host_and_scheme(
url=redirect_to,
allowed_hosts=self.get_success_url_allowed_hosts(),
require_https=self.request.is_secure(),
)
return redirect_to if url_is_safe else ""
def get_success_url_allowed_hosts(self):
return {self.request.get_host(), *self.success_url_allowed_hosts}
def get_default_redirect_url(self):
"""Return the default redirect URL."""
if self.next_page:
return resolve_url(self.next_page)
raise ImproperlyConfigured("No URL to redirect to. Provide a next_page.")
属性 | 説明 |
---|---|
next_page | デフォルトのリダイレクト先のURLを格納します。get_default_redirect_url メソッドで使用され、このURLが設定されていない場合にはエラーが発生します。 |
redirect_field_name | リダイレクトのためのフィールド名を指定する属性です。リダイレクト先のURLを含むリクエストのパラメーター名を定義します |
success_url_allowed_hosts | 安全と見なされるホストのセットを格納します。リダイレクト先のURLがこのセットに含まれるホストによって提供されている場合にのみ、そのURLは安全と見なされます。 |
FormViewクラス
フォームの表示と処理を行います。
TemplateResponseMixin
とBaseFormView
を継承し、テンプレートレスポンスの生成とフォームの基本的な操作を提供します。
class FormView(TemplateResponseMixin, BaseFormView):
継承① TemplateResponseMixinクラス
テンプレートを使ってレスポンスを生成する機能を提供します。
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]
render_to_response
メソッドは、指定されたテンプレートとコンテキストデータを使用して、TemplateResponseオブジェクトを生成します。
このオブジェクトを使用して、最終的なHTMLコンテンツをクライアント(ブラウザ)に送り返しています。
詳しくはこちらで説明しています。
継承② BaseFormViewクラス
BaseFormViewクラスはFormMixin
クラスとProcessFormView
クラスを継承しています
FormMixinクラス
フォームの基本的な操作を行い、FormMixin
とProcessFormView
を継承します。
class FormMixin(ContextMixin):
initial = {}
form_class = None
success_url = None
prefix = None
def get_initial(self):
return self.initial.copy()
def get_prefix(self):
return self.prefix
def get_form_class(self):
return self.form_class
def get_form(self, form_class=None):
if form_class is None:
form_class = self.get_form_class()
return form_class(**self.get_form_kwargs())
def get_form_kwargs(self):
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):
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):
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))
def get_context_data(self, **kwargs):
if "form" not in kwargs:
kwargs["form"] = self.get_form()
return super().get_context_data(**kwargs)
このクラスからLoginView
クラスでオーバーライドしているメソッドは、get_form_class
、get_form_kwargs
,form_valid
,get_context_data
となっています。
また、get_form_kwargs
の説明で、get_initial
とget_prefix
メソッドの説明もしているので、get_form
のみ説明します。
get_form
form_class属性が設定されていない場合、get_form_classメソッドを使って取得します。
ProcessFormViewクラス
主にフォームの表示と処理を担当する基本的なビュークラスです。
HTTPのGETリクエストに対してフォームをレンダリングし、POSTリクエストでフォームのデータを処理するために使用されます。
class ProcessFormView(View):
def get(self, request, *args, **kwargs):
return self.render_to_response(self.get_context_data())
def post(self, request, *args, **kwargs):
form = self.get_form()
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
def put(self, *args, **kwargs):
return self.post(*args, **kwargs)
View
クラスを継承していますが、このクラスはリクエストメソッドに応じてそれに対応する名前のメソッドを実行しています。
つまりGETリクエストやPOSTリクエストを受け取れば、上記ProcessFormView
クラスの対応するメソッドが実行されるということです。
Viewの基底クラスについての説明はこちら