このページでは LoginView
の使い方について説明していきます。
この LoginView
は View
というクラスのサブクラスの1つであり、ビューをクラスベースで作成する際に利用するクラスとなります。この View のサブクラス
を継承し、さらにクラス変数を定義したりメソッドをオーバーライドすることで、あなたが開発したいアプリに応じたビューを作成することが可能となります。
この辺りのクラスベースビューやクラスベースビューの作り方については下記ページで解説していますので、詳しくはこちらをご参照ください。
【Django入門14】クラスベースビューの基本そして、名前の通り LoginView
はログインを実現するための View のサブクラス
となります。関数ベースビューでの解説にはなりますが、ログイン機能を持つウェブアプリに必要となる動作や処理については下記ページでまとめていますので、事前にこちらの前半だけでも読んでおくことをオススメします。
このページで目指すことは、LoginView
を利用し、上記ページで紹介しているログイン機能を持つウェブアプリに必要な動作や処理をクラスベースビューで実現していくことになります。
Contents
LoginView
まずは、LoginView
がどういったクラスであるのかについて解説していきたいと思います。
名前の通り、LoginView
はログインを行うビューを実現するクラスとなります。
auth
アプリから提供されるクラス
このサイトでは今まで View のサブクラス
として CreateView
や UpdateView
を紹介してきましたが、これらは django.views.generic
から提供されるクラスでした。そのため、これらは django.views.generic
から import
して利用する必要がありました。
それに対し、LoginView
は django.contrib.auth.views
から import
して利用することになります。
from django.contrib.auth.views import LoginView
LoginView
は auth
というアプリで定義されるクラスとなりますので、上記のように import
の仕方が他の View のサブクラス
とは異なる点に注意してください。
また、auth
アプリでは、下記のように認証やログイン等を実現するためのクラスや関数等が多数定義されています。
- ユーザーを管理するモデルクラス;
User
- ユーザー登録用のフォームクラス;
UserCreationForm
- ログイン用のフォームクラス:
AuthenticationForm
- 認証を行う関数:
authenticate
- ログインを行う関数:
login
そして、今回扱う LoginView
は、ここで紹介したようなクラスや関数を利用してログインを実現するビューとなります。ここで紹介したクラスや関数は以降の解説でも出てきますので、頭の片隅ででも覚えておいていただければと思います。
スポンサーリンク
LoginView
の処理の流れ
続いて LoginView
の処理の流れについて説明しておきます。LoginView
では、GET
リクエストを受け取った際のログインページの表示と POST
リクエストを受け取った際の認証・ログイン処理によってログイン機能が実現されるようになっています。
LoginView
は、まず GET
リクエストを受け取った際にログイン用のフォームを含むログインページの表示を行います。このログイン用のフォームとは、先ほども紹介した AuthenticationForm
となります。この AuthenticationForm
ではユーザー名を入力する username
フィールドとパスワードを入力する password
フィールドが定義されており、ログインページ表示時にはこれらのフィールドを持つログイン用のフォームが表示されることになります。
このフォームから username
フィールドと password
フィールドを含むデータが POST
リクエストとして送信されてきた際、LoginView
は username
フィールドの値(ユーザー名)と password
フィールドの値(パスワード)に基づいて認証を実施します。この認証では、入力されたユーザー名に対するパスワードが正しいかどうかの判断が行われます。また、この認証は AuthenticationForm
のインスタンスから is_valid
メソッドを実行させることで行われます(より細かくいうと、is_valid
メソッドから先ほど紹介した authenticate
関数が実行されて認証が行われることになります)。
そして、認証が OK の場合のみ、username
フィールドに入力されたユーザー名のユーザーに対するログイン処理を実施します。このログイン処理は login
関数の実行によって行われます。さらに、ログイン処理の後に特定の URL に対するリダイレクトレスポンスを返却します。
認証が NG の場合、例えば入力されたユーザー名のユーザーが登録されていない、入力されたパスワードが登録されているものと一致しないような場合は、再度ログイン用のフォームが表示されることになります。
このように、LoginView
はログインを行うために必要となる “ログイン用のフォームの表示” や “認証処理”・”ログイン処理” が行われるように実装されているビューとなります。
認証について補足しておくと、認証処理においては、フォームから送信されてきた username
フィールドの値および password
フィールドの値と同じフィールドの値を持つレコードがデータベースに存在するかどうかの確認が行われます
存在すれば認証 OK となります
デフォルトでは、そのようなレコードが存在するかどうかの確認は User
という auth
アプリで定義されるモデルクラスに対応するテーブルに対して行われます
そのため、認証で OK となるためには事前に User
のテーブルにレコードを保存しておく必要があります
この辺りは、一般的なウェブアプリで事前にユーザー登録をしておかないとログインができないのと一緒です
クラスベースビューの場合、この User
のテーブルへのレコードの保存は CreateView
によって実現可能です
実際にユーザーを登録する例は LoginView の利用例 で示します
ログイン後のリダイレクト
この LoginView
におけるポイントの1つはログイン後のリダイレクトになると思います。前述の通り、LoginView
はログインに成功した後に特定の URL に対するリダイレクトレスポンスを返却します。そして、クライアント側はそのレスポンスを受け取り、指定された URL にリクエストを送信するようになります。
LoginView
では、このログイン後のリダイレクト先の URL は下記の3段階の判断が行われて自動的に設定されるようになっています。上側のものから順番に判断が行われ、当てはまる URL がリダイレクト先に設定されるようになっています。
POST
リクエストで送信されてくるデータにnext
フィールドが存在する時:next
で指定される URL にリダイレクト
- クラス変数
next_page
が定義されている時:next_page
で指定される URL にリダイレクト
- プロジェクトの
settings.py
でLOGIN_REDIRECT_URL
が定義されている時;LOGIN_REDIRECT_URL
で指定される URL にリダイレクト
1. 〜 3. の全てに当てはまらない場合はリダイレクト先として /accounts/profile/
が設定されることになります(LOGIN_REDIRECT_URL
のデフォルト値)。
ログイン前にアクセスしようとしたページへのリダイレクト
特にポイントになるのが 1. のリダイレクトです。このリダイレクトを利用することで、ユーザーをログイン後に “ログイン前にアクセスしようとしたページ” に自動的に遷移させることが可能となります。
まず、前述の通り、LoginView
では POST
リクエストによって認証とログイン処理が実施されることになります。POST
リクエスト時に送信されてくるユーザー名(username
フィールドの値)やパスワード(password
フィールドの値)に基づいて認証及びログインが行われることになります。
さらに、LoginView
では POST
リクエストによって送信されてくるデータに next
フィールドが存在し、その next
フィールドの値が URL として妥当である場合、ログイン後に、その next
フィールドで指定される URL をリダイレクト先とするリダイレクトレスポンスを返却するようになっています。
その一方で、ログイン機能を搭載したウェブアプリにおいては、非ログイン状態ではアクセスを拒否するページを設けることが多いです。”見たいページにアクセスしようとしたけれど、ログインしていないため表示が拒否されてログインページにリダイレクトされてしまった” という経験をお持ちの方も多いのではないでしょうか?
こういった “非ログインユーザーのアクセスの拒否” は Django でも可能で、この場合、非ログインユーザーがページにアクセスしようとするとログインページの URL へ強制的にリダイレクトされることになります。
もちろん、このリダイレクト先のログインページからログインを実施することは可能ですが、ユーザーが元々アクセスしたかったのはログインページの URL ではなく “ログイン前にアクセスしようとしていた URL” です。なので、ログイン後には “ログイン前にアクセスしようとしていた URL” にリダイレクトしてあげるのが親切ですよね。
このようなログイン後の “ログイン前にアクセスしようとしていた URL” へのリダイレクトを実現するために、先ほど説明した next
フィールドが利用されることになります。
前述の通り、POST
リクエスト時に LoginView
が next
フィールドを含むデータを受け取れば、自動的に LoginView
がログイン後に next
フィールドで指定される URL へのリダイレクトレスポンスを返却してくれることになります。
したがって、next
フィールドに “ログイン前にアクセスしようとしていた URL” がセットされたデータを POST
リクエスト時に LoginView
へ送信されるようにしてやれば、上記のようなリダイレクトが可能ということになります。もちろん、ログインを行うためには username
フィールドと password
フィールドも一緒に送信されるようにしておく必要があります。
そして、ログインを行うための POST
リクエストの送信はログインページから行われることになります。なので、ログインを実施する際に “ログイン前にアクセスしようとしていた URL” が値にセットされた next
フィールドを含んだデータを送信するようにログインページを作ってやれば、上記のようなリダイレクトが可能となります。ページを構成するのは HTML であり、その HTML はテンプレートファイルから生成されることになるため、つまりはテンプレートファイルを上記のように作成する必要があります。
この辺りのテンプレートファイルの作り方の詳細に関しては、次の LoginView でのクラスベースビューの作り方 で解説していきます。まずは、”ログイン前にアクセスしようとした URL” へのリダイレクトが可能であることと、そのために POST
リクエスト時に next
フィールドを含むデータが送信されるようにすることが必要であることを覚えておいていただければと思います。
また、上記のようなリダイレクトを実現する上では非ログインユーザーからのアクセスを拒否する設定もビューに対して行う必要があります。これについても次の LoginView でのクラスベースビューの作り方 で解説していきます。
LoginView
でのクラスベースビューの作り方
では、次は LoginView
でクラスベースビューを作成する手順について説明していきます。
LoginView
でのクラスベースビューの作り方に関しても基本的には他の View のサブクラス
と同じです。
つまり、views.py
に LoginView
を継承するクラス(サブクラス)を定義し、views.py
に定義したクラスにクラス変数やメソッドを定義することで LoginView
で定義されているクラス変数の上書き・メソッドのオーバーライドを行なっていきます。これにより、LoginView
の特徴を活かしながら自身のウェブアプリに応じたビューにカスタマイズしていくことが可能となります。
また、LoginView
ではリクエストに応じて異なる処理が行われるようになっており、GET
リクエストを受け取った際には get
メソッドが、POST
リクエストを受け取った際には post
メソッドが実行されるようになっています。そして、LoginView
のクラス変数や他のメソッドは、これらの get
メソッドおよび post
メソッドから利用されるようになっています。したがって、LoginView
のサブクラス側でクラス変数やメソッドを上書き・オーバーライドしてやれば、この get
メソッドと post
メソッドの動作を変化させることができます。
スポンサーリンク
最低限のカスタマイズで利用可能
CreateView
や FormView
等の他の View のサブクラス
は基本的に開発者がカスタマイズすることを前提として用意されているビューとなります。それに対し、LoginView
は FormView
をカスタマイズすることで作られたビューで、LoginView
はログインに特化する形で既に作り込まれたビューとなります。
そのため、LoginView
に関しては最低限のカスタマイズのみで利用可能なビューとなっています。
例えば、CreateView
のサブクラスではクラス変数 form_class
(or model
+ fields
) の定義を行なってビューで扱うモデルフォームクラスを必ず指定する必要がありました。これは、CreateView
がどんなモデルフォームクラスでも対応できるような汎用的な作りになっているからになります。
それに対し、LoginView
に関してはログインに特化しているため、あらかじめログイン用フォームとして form_class
に AuthenticationForm
が指定されるようになっています。そのため、LoginView
のサブクラスではわざわざカスタマイズを行って扱うフォームクラスを指定する必要はありません。
このように、LoginView
はログインに特化する形で既に作り込まれているため、最低限のカスタマイズで利用可能となります。
他のビューのアクセス制限
ただし、ログイン機能を搭載するウェブアプリにおいては、LoginView
のサブクラス以外のビューに対して別途カスタマイズが必要になることが多いので、その点には注意が必要です。
ログイン機能を搭載するウェブアプリの場合、非ログインユーザーからのアクセスを拒否したいページが存在することが多いです。そもそもログインしないと利用できないウェブアプリも多いですよね。
LoginRequiredMixin
の継承
そういった非ログインユーザーからのアクセスを拒否するページを実現するためには、そのページの表示を行うビューに LoginRequiredMixin
を継承させる必要があります。
例えば、下記のような CommentList
によって表示されるページは、非ログインユーザーからもアクセス可能となります。
from django.views.generic import ListView
from .models import Comment
class CommentList(ListView):
model = Comment
それに対し、下記のように LoginRequiredMixin
を継承させるようにした場合、非ログインユーザーからのアクセスは不可となります。
from django.views.generic import ListView
from .models import Comment
from django.contrib.auth.mixins import LoginRequiredMixin
class CommentList(LoginRequiredMixin, ListView):
model = Comment
このように、ログイン機能を搭載するウェブアプリを開発する場合は LoginView
のサブクラスだけでなく他のビューに対するケアも必要になります。また、クラスベースビューの場合は上記のように LoginRequiredMixin
を継承させるようにすれば良いのですが、関数ベースビューの場合は @login_required
というデコレーターを利用することになります。詳細は下記ページを参照してください。
LoginRequiredMixin
によるリダイレクト
上記のように非ログインユーザーからのアクセスを拒否した場合、非ログイン状態でそのページにアクセスした場合には特定の URL に強制的にリダイレクトされることになります。この強制的なリダイレクトによって、非ログインユーザーからのアクセスを禁止する仕組みとなっています。
このリダイレクト先の URL は下記となります。
LOGIN_URL/?next=ログイン前にアクセスしようとしたURL
LOGIN_URL
は settings.py
で設定するパラメーターで、LOGIN_URL
を指定しなかった場合はデフォルト設定の /accounts/login/
が指定されることになります。この LOGIN_URL
にはログインページの URL を設定しておくことが一般的です。そして、ログインページは LoginView
によって実現されるため、このリダイレクトによってクライアントから LoginView
に対してリクエストが送信されることになります。
例えばアプリのログインページの URL が /forum/login/
であり、さらに非ログインユーザーの /forum/comments/
の URL へのアクセスが LoginRequiredMixin
によって拒否されているとしましょう。この場合、settings.py
で LOGIN_URL = '/forum/login/'
を定義しておけば、非ログイン状態で /forum/comments/
にアクセスすると下記 URL にリダイレクトされることになります。
/forum/login/?next=/forum/comments/
/forum/login/
はログインページの URL であるため、このリダイレクトによってログインページが表示されることになり、ユーザーはこのページでログインを実施することができます。
また、上記における next
以降に関しては ログイン前にアクセスしようとしたページへのリダイレクト で説明したようなリダイレクトを実現するためのクエリパラメーターとなります。
非ログイン状態のユーザーから LoginRequiredMixin
を継承するビューに紐づけられた URL へのアクセスが発生した際、LoginRequiredMixin
によってログインページへリダイレクトされ、その際に上記のように URL にクエリパラメーター next
が付加されることになります。そして、この next
には “ログイン前にアクセスしようとしていた URL” が指定されることになります。上記の場合は /forum/comments/
にアクセスしようとしてログインページにリダイレクトされるため、next
には /forum/comments/
が指定されることになります。
このクエリパラメーター next
を利用することで、ログイン後の “ログイン前にアクセスしようとしていた URL” へのリダイレクトが実現可能となります。この点については次の節で説明していきます。
ログイン後のリダイレクト先の設定
また、LoginView
では POST
リクエストを受け取ってログインを行なった後にリダイレクトレスポンスの返却が行われることになります。このレスポンスにおけるリダイレクト先の設定に関しても LoginView
のサブクラスを利用する上で重要なポイントとなります。
POST
リクエストを受け取った際にリダイレクトレスポンスを返却する点に関して言えば CreateView
や UpdateView
等も同様です。これらのビューの場合は、リダイレクト先の URL はクラス変数 success_url
の定義や get_success_url
のオーバーライドによって設定可能でした。
それに対し、LoginView
の場合はクラス変数やメソッドのオーバーライドだけでなく、ログイン後のリダイレクト で説明したように、ログイン前にアクセスしようとしていた URL や settings.py
での LOGIN_REDIRECT_URL
の定義によってリダイレクト先の URL が設定されることになります。
特に LoginView
の特徴になるのが、ログイン前にアクセスしようとしていた URL へのリダイレクトになります。この概要に関しては ログイン前にアクセスしようとしたページへのリダイレクト で解説しましたが、ここではこのリダイレクトの具体的な実現方法についてここで解説しておきたいと思います。
next
へのリダイレクト
ログイン前にアクセスしようとしたページへのリダイレクト で説明したように、LoginView
は POST
リクエスト時に受け取ったデータに next
フィールドが存在する場合、その next
フィールドに指定された URL をリダイレクト先とするリダイレクトレスポンスをログイン実施後に返却するようになっています(next
フィールドの値が空文字列の場合は next
フィールドは無視されることになります)。
そのため、この next
フィールドに “ログイン前にアクセスしようとしていた URL” がセットされていれば、ログイン後に “ログイン前にアクセスしようとしていた URL” へのリダイレクトレスポンスを返却することができることになります。これを受け取ったクライアントはログイン状態で “ログイン前にアクセスしようとしていた URL” にリダイレクトされることになり、元々表示したかったページ等の閲覧が可能となります。
そして、前述の通り、ログイン前のアクセスが許可されないページにアクセスした際には LoginRequiredMixin
によってログインページ(LoginView
)にリダイレクトされ、その際には URL のクエリパラメーター next
に “ログイン前にアクセスしようとしていた URL” がセットされることになります。
この時、LoginView
は GET
リクエストを受け取ることになり、クエリパラメーター next
も受け取ることになります。
ただ、”ログイン前にアクセスしようとしていた URL” へのリダイレクトを実現するためには、この next
にセットされている “ログイン前にアクセスしようとしていた URL” を GET
リクエスト時だけでなく POST
リクエスト時にも LoginView
が受け取れるようにする必要があります。
前述の通り、値が “ログイン前にアクセスしようとしていた URL” である next
フィールドを含むデータを POST
リクエスト時に LoginView
が受け取れるようにさえしてやれば、後はその URL へのリダイレクトレスポンスを LoginView
が自動的にクライアントに返却するようになります(POST
リクエストが送信される目的はログインを行うことですので、そのための username
フィールドや password
フィールドも必要になります)。
では、値が “ログイン前にアクセスしようとしていた URL” である next
フィールドを含むデータを POST
リクエスト時に LoginView
が受け取れるようするにはどうすれば良いでしょうか?
これに関しても ログイン前にアクセスしようとしたページへのリダイレクト で少し説明しましたが、ログイン時に POST
リクエストを送信するのはログインページであるため、ログインページから username
フィールドと password
フィールドに加え、値が “ログイン前にアクセスしようとしていた URL” である next
フィールドを含むデータを送信するようにしてやれば良いことになります。そして、ログインページは HTML によって表示され、さらにこの HTML は Django ではテンプレートファイルから生成されます。そのため、フォームから next
フィールドを含むデータが送信されるようにテンプレートファイルを作成してやれば良いことになります。
これにより、GET
リクエスト時に生成された HTML をレスポンスとして受け取ったクライアントがフォームからログインに必要な username
フィールドと password
フィールドを送信してログインしようとした際に、これらのデータに加え、値が “ログイン前にアクセスしようとしていた URL” である next
フィールドが送信されるようになります。
具体的には、このようなテンプレートファイルは下記のように、<form>
〜 </form>
に name="next"
と value="{{ next }}"
の属性を指定した <input>
タグを追加することで実現することができます。ちなみに type="hidden"
を指定するのは、このフィールドを非表示にするためです。このフィールドはユーザーから入力してもらうためのものではないため非表示にしておきます。
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<input type="hidden" name="next" value="{{ next }}">
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
上記では 'login'
は LoginView
のサブクラスに紐付けされた URL であることを前提としています。さらに form
はフォームクラスのインスタンスであることを前提としています。前述の通り、デフォルトでは form
は AuthenticationForm
のインスタンスとなります。
詳細に関しては LoginView が生成するコンテキスト で説明しますが、LoginView
が生成するコンテキストには form
フィールドと next
フィールドが存在します。そして、コンテキストの next
フィールドの値はクエリパラメーター next
で指定される値となります。したがって、LoginRequiredMixin
によるリダイレクトによって LoginView
が GET
リクエストを受け取った際には、コンテキストの next
フィールドの値は “ログイン前にアクセスしようとしていた URL” となります。
そのため、上記のように name="next"
と value="{{ next }}"
の属性を指定した input
タグを <form>
〜 </form>
の間に追加してやれば、送信
ボタンクリック時に AuthenticationForm
の持つ username
フィールドと password
フィールドの値だけでなく、値が “ログイン前にアクセスしようとしていた URL” である next
フィールドも送信されるようになります。
そして、フォームからのデータ送信時には POST
リクエストが送信されますので、LoginView
は POST
リクエスト時に next
フィールドを含むデータを受け取ることができるようになり、これによって “ログイン前にアクセスしようとしていた URL” へのリダイレクトを実現できることになります。
長々と説明してきたので “ログイン前にアクセスしようとしていた URL” へのリダイレクトは複雑なようにも思えたかもしれませんが、基本的には実現に必要となる実装はテンプレートファイルへの上記のような input
のタグの追加のみで、あとは LoginView
を継承するビューや LoginRequiredMixin
を継承するビューを用意しておけば、これらのビューが適切にパラメーター next
を扱って “ログイン前にアクセスしようとしていた URL” が自然と実現されることになります。
next
フィールドが存在しない場合のリダイレクト
また、”ログイン前にアクセスしようとしていた URL” へのリダイレクトが不要であるのであれば、テンプレートファイルへの上記のような input
のタグの追加を行わなければ良いです。これにより、フォームから送信されるデータに next
フィールドが含まれなくなるため、”ログイン前にアクセスしようとしていた URL” へのリダイレクトが行われなくなります。
そして、フォームから送信されるデータに next
フィールドが存在しない場合は、ログイン後のリダイレクト でも説明したように、”LoginView
のサブクラスで定義したクラス変数 next_page
” or “settings.py
で定義した LOGIN_REDIRECT_URL
” にリダイレクトされることになります。
これらのどちらか一方を定義しておけば十分ですが、もし両方を定義していた場合は next_page
の方が優先されることになります。また、POST
リクエスト時に送信されてくるデータに next
フィールドが存在しない場合や next
フィールドの値が空文字列の場合、上記のいずれかを定義していないと /accounts/profile/
へリダイレクトされることになります。
クエリパラメーター next
が存在しない場合のリダイレクト
さらに、ログインページ表示時に URL にクエリパラメーター next
が存在しない場合もあり得ます。前述の通り、非ログイン状態でアクセス不可なページを表示するビューを LoginRequiredMixin
の継承によって定義しておけば、そのページに非ログイン状態でアクセスされた際にログインページへのリダイレクトが行われ、この際にクエリパラメーター next
がリダイレクト先の URL に付加されることになります。
ですが、直接ログインページにアクセスされた際にはクエリパラメーター next
が設定されません。そして、これは普通にあり得るユースケースとなります。
この場合、クエリパラメーター next
が存在しないわけですから next へのリダイレクト で紹介したようなテンプレートファイルを用意したとしても、POST
リクエスト時に送信されるデータにおける next
フィールドは空文字列となります。そのため、next
フィールドで指定される URL のリダイレクトは不可となります。
そして、この場合も先ほどと同様に、”LoginView
のサブクラスで定義したクラス変数 next_page
” or “settings.py
で定義した LOGIN_REDIRECT_URL
” にリダイレクトされることになります。
このように、クエリパラメーター next
が指定されない場合もケアしてリダイレクト先を設定しておく必要がある点に注意が必要です。
以上が、LoginView
を利用してビューを作成する場合のポイントとなります。
他の View のサブクラス
と同様の作り方にはなるのですが、LoginView
に関しては既にログイン用途のビューとして作り込まれているためカスタマイズ要素は少ないです。
ですが、ログイン機能を有するウェブアプリに開発していく際には、非ログインユーザーからのアクセスを拒否するために他のビューで LoginRequiredMixin
を継承させる必要がある場面も多いと思います。また、ログイン機能を搭載した際にはリダイレクトが様々な場面(非ログインユーザーがアクセス不可なページにアクセスした時、ログインに成功した時など)で行われますので、このリダイレクトについても理解しておくと良いと思います。
スポンサーリンク
LoginView
のクラス変数
では、次は LoginView
で定義されているクラス変数の紹介を行なっていきます。これらのクラス変数を LoginView
を継承するクラスで定義し直して上書きすることでクラスの動作のカスタマイズを行うことが可能となります。
LoginView
の場合、GET
メソッドのリクエストを受け取った際に get
メソッドが実行され、POST
メソッドのリクエストを受け取った際に post
メソッドが実行されることになるため、これらの get
メソッドや post
メソッドの動作を変化させることを目的にクラス変数の定義を行なっていくことになります。
LoginView
のクラス変数の一覧
この LoginView
で定義されるクラス変数には下記のようなものが存在します。
- form_class
- authentication_form
- next_page
- redirect_field_name
- redirect_authenticated_user
- template_name
- extra_context (
ListView
) - initial (
CreateView
) - prefix (
CreateView
) - template_engine (
ListView
) - response_class (
ListView
) - content_type (
ListView
)
後半に示したクラス変数に関しては他の View のサブクラス
の解説ページで既に説明済みです。そのため、各クラス変数のテキストには、それらのページへのリンクを貼っています。他のページにジャンプするリンクテキストの横には括弧内でジャンプ先のページを示していますので、これらのクラス変数の詳細を知りたい方はリンク先の説明を参照していただければと思います。
ここでは、上記の前半部分に示した、特に LoginView
ならではの特徴を持つクラス変数について説明していきます。
form_class
form_class
は LoginView
のサブクラスで扱うフォームクラスを指定するクラス変数になります。CreateView
や UpdateView
、さらには FormView
等も同じクラス変数を持っていますが、LoginView
の場合はログイン用(認証用)のフォームクラスを指定する必要があります。ここが他の View のサブクラス
とは異なります。
また、LoginView
の場合、クラス変数 form_class
を定義しなくても、デフォルトで form_class
に AuthenticationForm
が指定されるようになっているため、form_class
を定義しなくても自動的にLoginView
が利用するフォームクラスが設定されるようになっています。
そして、この AuthenticationForm
はユーザー名とパスワードの入力フィールドが定義されたクラスになります。このクラスのインスタンスに is_valid
メソッドを実行させればパスワード認証が実行されます(is_valid
メソッドは LoginView
が POST
リクエストを受け取った際、ユーザーが入力したユーザー名やパスワードに対して実施されるようになっています)。このように、AuthenticationForm
はログイン用フォームとして必要なフィールドや機能を備えており、基本的には form_class
は定義せず、デフォルトの AuthenticationForm
を利用するのでよいと思います。
それでも AuthenticationForm
以外のフォームクラスを LoginView
のサブクラスに利用させるようにしたいのであれば、次に説明する authentication_form
を定義してやれば良いです。
スポンサーリンク
authentication_form
authentication_form
も基本的には form_class
と同様の意味合いのクラス変数になります。すなわち、LoginView
のサブクラスが利用するフォームクラスを指定します。ただし、authentication_form
が定義されてフォームクラスが指定されている場合は、form_class
ではなく authentication_form
の方が優先して利用されるようになります。
したがって、LoginView
のサブクラスで form_class
と authentication_form
の両方が定義されていない場合は AuthenticationForm
が自動的に LoginView
のサブクラスが利用するフォームクラスとして設定されることになりますが、authentication_form
を定義しておけば LoginView
のサブクラスの利用するフォームクラスとして AuthenticationForm
以外のものを設定することが可能となります(別に form_class
を定義して AuthenticationForm
から変更するのでも良いです)。
ただし、クラス変数 authentication_form
を定義する場合、基本的には authentication_form
には “AuthenticationForm
のサブクラス” を指定する必要があるという点に注意してください。単なるフォームクラス(forms.Form
のサブクラス)を authentication_form
に指定してもウェブアプリ動作時に例外が発生することになります。
next_page
next_page
は ログイン後のリダイレクト先の設定 で説明したようにログイン後のリダイレクト先を指定するためのクラス変数になります。next_page
のデフォルトは None
で、next_page
が None
の場合は settings.py
で定義した LOGIN_REDIRECT_URL
で指定した URL がログイン後のリダイレクト先の URL に設定されることになります。また、”ログインフォームから送信されてきたデータに next
フィールドが存在する” & “next
フィールドが空文字でない” 場合は next_page
よりも next
で指定された URL がリダイレクト先の URL として優先して設定されることになります。
さらに、next_page
には URL そのものではなく URL の名前などを指定することも可能です。
redirect_field_name
先ほども少し説明しましたが、”ログインフォームから送信されてきたデータに next
フィールドが存在する” & “next
フィールドが空文字でない” 場合、LoginView
のサブクラスはログイン後に next
フィールドの値となる URL に対するリダイレクトレスポンスを返却します。
このリダイレクト先となる URL を指定するフィールドのフィールド名 next
は、ここで説明するクラス変数 redirect_field_name
の定義により変更することが可能です。
例えば下記のようにクラス変数 redirect_field_name
を定義した場合、ログインフォームから送信されてきたデータの redirect
フィールドが空文字でない場合に UserLoginView
はログイン後に redirect
フィールドの値となる URL に対するリダイレクトレスポンスを返却するようになります。
class UserLoginView(LoginView):
template_name = 'accounts/login.html'
redirect_field_name = 'redirect'
ただし、このようにクラス変数 redirect_field_name
を定義しただけでは next へのリダイレクト で説明したような処理の流れが実現できないので注意してください。
クラス変数 redirect_field_name
を定義した場合、redirect_field_name
の指定値に応じて LoginView
のサブクラスが GET
リクエスト時に取得しようとするクエリパラメーターの変数名も変化します。例えば上記のように UserLoginView
を定義した場合、この UserLoginView
はクエリパラメーター redirect
からコンテキストにセットする URL を取得するようになります。また、コンテキストのキー名も 'redirect'
に変化することになります。
それに対し、クエリパラメーターをセットするのは LoginRequiredMixin
の役目であり、前述の通り、デフォルトでは LoginRequiredMixin
はリダイレクト先とする URL をクエリパラメーターの next
にセットするようになっています。
つまり、LoginView
のサブクラスで redirect_field_name
を変更してしまうと、LoginRequiredMixin
の動作と話が合わなくなってしまうことになります。そのため、LoginView
のサブクラスで redirect_field_name
を変更する場合、LoginRequiredMixin
を継承するクラス側の設定も変更が必要となります。
具体的には、LoginRequiredMixin
でもクラス変数 redirect_field_name
が定義されているため、LoginRequiredMixin
を継承する側のビューでもクラス変数 redirect_field_name
を定義して指定値を変更する必要があります。そして、そのクラス変数 redirect_field_name
への指定値は LoginView
のサブクラス側と合わせる必要があります。
また、コンテキストにセットされているデータを参照するのはテンプレートファイルですので、next
ではなく redirect_field_name
に指定されている名前の変数を参照するようにする必要があります。さらに、フォームから送信されるデータに redirect_field_name
の名前のフィールドが含まれるようにするため、フォームから送信されるデータの名称が redirect_field_name
の指定値となるよう、追加する input
タグの name
属性を変更する必要もあります。
下記は、redirect_field_name = 'redirect'
とした場合のテンプレートファイルにおける form
タグ部分の例となります。
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<input type="hidden" name="redirect" value="{{ redirect }}">
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
こんな感じで、redirect_field_name
を変更すると様々な実装箇所に影響を及ぼすことになるので注意してください。また、よっぽどのことがない限り変更する必要もないと思います。一応 LoginView の利用例 でクラス変数 redirect_field_name
の変更例を紹介します。
スポンサーリンク
redirect_authenticated_user
redirect_authenticated_user
はログイン済みのユーザーが再度ログインページにアクセスした場合の動作を決定するクラス変数です。具体的には、ログイン済みのユーザーが LoginView
のサブクラスが表示するページにアクセスしてきた際、redirect_authenticated_user
が False
の場合はそのままログインページを表示されることになります。
それに対し、 redirect_authenticated_user
が True
の場合は他のページへのリダイレクトが行われるようになります。つまり、ログイン状態のユーザーはログインページを表示できなくなります。既にログイン済みのユーザーにログインページを表示する必要もないので、他のページにリダイレクトするというわけです。
そして、このリダイレクト先はログイン後のリダイレクトと同様の仕組みで決定されることになります。ただし、基本的には既にログイン済みのユーザーが直接ログインページにアクセスしてきた時に発生するリダイレクトとなるためクエリパラメーター next
は設定されることがなく、クラス変数 next_page
or settings.py
で定義した LOGIN_REDIRECT_URL
に指定されている URL にリダイレクトが行われることになるはずです。
redirect_authenticated_user
のデフォルト値は False
となりますので、ログイン済みのユーザーが再度ログインページにアクセスした際にリダイレクトするようにしたいのであればクラス変数 redirect_authenticated_user
を定義し、True
を指定しておく必要があります。
template_name
template_name
は、他の View のサブクラス
同様に LoginView
のサブクラスが利用するテンプレートファイルを指定するクラス変数となります。デフォルトは 'registration/login.html'
となります。
LoginView
のメソッド
次に LoginView
の持つメソッドを紹介していきます。LoginView
を継承したクラスを定義し、そのクラスで LoginView
の持つメソッドをオーバーライドしてやることで LoginView
とは異なる動作のクラスを実現することができるようになります。
ここまでの解説の中でも何回か説明しましたが、LoginView
はログイン用のビューとして既に作り込まれているため、メソッドのオーバーライドを行う機会は少ないのではないかと思います。
ということで、ここではオーバーライドの例などは示さず、LoginView
のメソッドの一覧のみを示しておきたいと思います。
スポンサーリンク
LoginView
のメソッド一覧
LoginView
の持つメソッドの一覧は下記のようになります。あくまでもクラスのカスタマイズ目的でオーバーライドを行う可能性のあるものを挙げており、as_view
などのカスタマイズは行わないであろうメソッドは省略しています。
dispatch
:リクエストや設定に応じた処理の振り分けを行う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_redirect_url
:非ログイン状態でアクセスしようとしていた URL を取得するget_default_redirect_url
:next_page
orLOGIN_REDIRECT_URL
で指定される URL を取得するget_template_names
:テンプレートファイルの名前を取得するrender_to_response
:レスポンスを返却する
ポイントとなるメソッドの1つが dispatch
となります。リクエストを受け取った際に最初に実行される LoginView
のメソッドは dispatch
となり、クラス変数 redirect_authenticated_user
が True
の場合、アクセスしてきたユーザーが既にログイン中であればリダイレクトが行われることになります。
それ以外の場合は、リクエストのメソッドの種類(GET
or POST
)に応じて get
or post
が dispatch
から実行されるようになっています。そして、これらの get
や post
の中から上記の各種メソッドが実行されるようになっています。
また、ログイン後のリダイレクト先の URL は get_success_url
メソッドから get_redirect_url
メソッドや get_default_redirect_url
メソッドが実行されることで決定されることになります。
LoginView
が生成するコンテキスト
続いて LoginView
が生成するコンテキストについて説明しておきます。
LoginView
は get_context_data
メソッドの中でコンテキストを生成し、その生成するコンテキストには下記の要素が含まれます。
'form'
:AuthenticationForm
のインスタンス'next'
:クエリパラメーターnext
で指定される URL'site'
:ログインしようとしているサイト(アプリ)の情報'site_name'
:ログインしようとしているサイト(アプリ)の名前
これらの中でテンプレートファイルから参照する機会が多いのが 'form'
と 'next'
になると思います。'form'
には AuthenticationForm
のインスタンスがセットされており、これをテンプレートファイルから {{ form.as_table }}
等で出力すれば、通常のフォームクラスと同様にフォームの表示を行うことができます。authentication_form で説明したように、クラス変数 authentication_form
を定義することで AuthenticationForm
以外のフォームクラスをテンプレートファイルから参照することができるようになります。
また、'next'
には “ログイン前にアクセスしようとしていた URL” がセットされることになりますので、next へのリダイレクト で紹介したようなテンプレートファイルを用意しておけば、この URL をフォームから送信することができるようになります。そして、それによってログイン後に “非ログイン状態でアクセスしようとしていたページの URL” へのリダイレクトを実現することができるようになります。
上記以外のデータをコンテキストにセットしてテンプレートファイルから参照できるようにしたい場合は、ListView
の解説ページの extra_context で説明しているクラス変数 extra_context
を定義したり、get_context_data
のオーバーライドを行なったりしてコンテキストの要素を追加することも可能です。
LoginView
の利用例
最後に、ここまでの説明のまとめとして、LoginView
を継承するクラスでのビューの作成例を示していきたいと思います。ここでは、LoginView
だけでなく、LogoutView
を利用したログアウトを実現する例や、非ログイン状態でアクセス不可なページとして ListView
を利用する例も示していきます。
スポンサーリンク
プロジェクトとアプリの作成
最初にいつも通りプロジェクトを作成していきしょう!。
まず、適当な作業フォルダに移動したのち、下記コマンドでプロジェクトを作成します。今回はプロジェクトを loginviewproject
としています。
% django-admin startproject loginviewproject
続いてアプリを作成していきます。先ほどのコマンドの実行で loginviewproject
というフォルダが作成されたはずなので、この loginviewproject
に下記の cd
コマンドで移動します。
% cd loginviewproject
続いて、下記コマンドを実行してアプリを作成します。今回はアプリを accounts
としています。
% python manage.py startapp accounts
また、先ほど cd
コマンドで移動した先のフォルダの中にも loginviewproject
というフォルダがあるはずなので、そのフォルダの下にある settings.py
を開き、下記のように INSTALLED_APPS
のリストを変更します。これにより、アプリ accounts
がプロジェクトに登録されることになります。
INSTALLED_APPS = [
'accounts', # 追加
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
フォームの定義とモデルの定義は省略
今回はフォームの定義とモデルの定義は行わず、auth
アプリで定義される AuthenticationForm
を LoginView
のサブクラスが扱うフォームクラスとし、さらにユーザーを管理するモデルクラスとして User
を利用します。これらは認証やログイン等の機能を備えたクラスとなります。
もし LoginView
のサブクラスが扱うフォームクラスを他のものにしたいのであれば、form_class や authentication_form で説明したように、これらのクラス変数を定義することで変更することも可能です。
また、ユーザーを管理するモデルクラスを User
から変更したい場合は “カスタムユーザー” を別途定義し、それを利用するようにする必要があります。というか、そもそもユーザーを管理するモデルクラスとしては User
をそのまま利用することは推奨されていません(お試しで開発するウェブアプリで利用することは問題ないです)。この辺りに関しては下記ページで解説していますので、必要に応じてご参照していただければと思います。
今回はお試しのウェブアプリを開発していくだけなので、User
をそのまま利用していきたいと思います。
マイグレーションの実施
今回は新たにモデルの定義は行いませんが、データベース内にテーブルは必要なので、そのテーブルの作成を行うためにマイグレーションを実施します。具体的には、今回のウェブアプリの場合、User
のインスタンスをレコードとして保存するためのテーブルや、セッション情報のレコードを保存するためのテーブルが必要となります。
今回はモデルクラスをは定義していないため、下記の1つのコマンドのみでマイグレーションが完結することになります。
% python manage.py migrate
スポンサーリンク
クラスベースビューの作成
続いて、このページの主題となっているクラスベースビューを作成していきます。今回は、ここまでの説明の通り LoginView
を継承するクラスを定義し、そのクラスをクラス変数の定義によってカスタマイズしていきます。また、ログアウトを実現するためのビューとして LogoutView
のサブクラスの定義も行います。さらに、非ログインユーザーがアクセス不可なページを実現するビューとして ListView
のサブクラス、ユーザーの新規登録を実現するビューとして CreateView
のサブクラスを定義していきます。
今回は、下記のように views.py
を変更し、LoginView
を継承するクラスとして UserLogin
を定義したいと思います。また、動作確認を目的に、LogoutView
を継承するクラスとして UserLogout
、ListView
を継承するクラスとして UserList
、CreateView
を継承するクラスとして UserRegistration
も定義しています。
from django.views.generic import CreateView, ListView
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login
from django.urls import reverse_lazy
class UserLogin(LoginView):
template_name = 'accounts/user_login.html'
redirect_field_name = 'redirect'
redirect_authenticated_user = True
class UserLogout(LogoutView):
pass
class UserRegistration(CreateView):
form_class = UserCreationForm
template_name = 'accounts/user_form.html'
success_url = reverse_lazy('list')
def form_valid(self, form):
response = super().form_valid(form)
user = self.object
login(self.request, user)
return response
class UserList(LoginRequiredMixin, ListView):
model = User
template_name = 'accounts/user_list.html'
redirect_field_name = 'redirect'
UserLogin
UserLogin
は、ここまで説明をしてきた LoginView
を継承するクラスであり、ユーザーログインを実現するビューとなります。
UserLogin
は GET
リクエストを受け取った際にはログインフォームを表示するための HTML を返却し、POST
リクエストを受け取った際にはフォームから送信されてきたデータに基づいて認証を行い、認証結果が OK の場合にはログインの実施および特定の URL へのリダイレクトレスポンスの返却を行います。
UserLogin
ではクラス変数 redirect_field_name
を定義して 'redirect'
を指定しているため、GET
リクエストの URL にクエリパラメーター redirect
が含まれる場合は、その後にログインを実施した際にクエリパラメーター redirect
で指定される URL へのリダイレクトレスポンスが返却されることになります。これは、ログイン前にアクセスしようとしたページへのリダイレクト で説明したリダイレクトになるのですが、redirect_field_name
を定義しているため UserLogin
がリダイレクト先として扱う URL の取得先がクエリパラメーターの next
から redirect
に変化している点に注意してください。
また、このようなリダイレクトレスポンスの返却を実現するためにはテンプレートファイル accounts/user_login.html
側での redirect
の扱いも必要となり、これについては後述で解説します。
さらに、UserLogin
ではクラス変数 redirect_authenticated_user
を定義して True
を指定しているため、ログイン中のユーザーからのアクセスによって UserLogin
が動作する際には即座に特定の URL へのリダイレクトレスポンスが返却されることになります。そして、この “特定の URL” は UserLogin
のクラス変数 next_page
で指定される URL or settings.py
の LOGIN_REDIRECT_URL
で指定される URL のどちらか一方となります。今回の例ではクラス変数 next_page
は定義しないため、後ほど settings.py
を変更して LOGIN_REDIRECT_URL
の定義を行い、LOGIN_REDIRECT_URL
に指定した URL にリダイレクトされるようにしていきます。
UserLogout
UserLogout
は LogoutView
を継承するクラスとなり、ユーザーログアウトを実現するビューとなります。
この LogoutView
に関しては下記ページで詳細を解説していますので、詳しくは下記ページを参照してください。
この UserLogout
に紐づけられた URL にアクセスすると、そのユーザーがログアウト状態になります。そして、その後に特定の URL へのリダイレクトレスポンスが返却されることになります。この “特定の URL” は、UserLogout
のクラス変数 next_page
で指定される URL or settings.py
の LOGOUT_REDIRECT_URL
で指定される URL のどちらか一方となります。今回の例ではクラス変数 next_page
は定義しないため、後ほど settings.py
を変更して LOGOUT_REDIRECT_URL
の定義を行い、LOGOUT_REDIRECT_URL
に指定した URL にリダイレクトされるようにしていきます。
UserRegistration
UserRegistration
は CreateView
を継承するクラスであり、ユーザーの新規登録を実現するビューとなります。より具体的には、UserRegistration
はフォームから送信されてきたデータに基づいて User
のインスタンスを生成し、それをレコードとしてデータベースに保存します。
この CreateView
に関しては下記ページで詳細を解説していますので、各クラス変数やメソッドの意味合いに関しては下記ページをご参照いただければと思います。
ログイン関連の情報のみを補足しておくと、UserLogin
が認証を実施する際にはユーザーがフォームに入力した情報と、この UserRegistration
によって保存されているレコードの username
と password
とが一致するかどうかの検証が行われることになります。
また、UserRegistration
ではクラス変数 form_class
に UserCreationForm
を指定しており、この UserCreationForm
がフォームとして表示されると username
(ユーザー名)と password
(パスワード)、さらには確認用のパスワードの3つのフィールドが表示されます。
そして、このフォームからデータが送信されてきた際には、入力された username
と password
がフィールドにセットされた User
のインスタンスがレコードとしてデータベースに保存されることになります。さらに、この password
は暗号化された状態(ハッシュ化された状態)で保存されることになります。
単なるモデルフォームクラスを定義し、それをクラス変数 form_class
に指定してユーザーを作成するようにするのでも良いのですが、暗号化などのセキュリティを考慮すると、ログイン用のユーザーを新規登録するための CreateView
のサブクラスでは、クラス変数 form_class
には UserCreationForm
を指定するのが良いです。もしくは UserCreationForm
のサブクラスを指定するのでも良いです。
さらに、UserRegistration
では form_valid
を定義してオーバーライドを行なっており、CreateView
の form_valid
が行う処理に加え、login
関数によるログイン処理も実行するようになっています。そのため、ユーザーの新規登録に成功した際には、そのユーザーでのログインが自動的に実施されることになります。
UserList
UserList
は ListView
を継承するクラスであり、ユーザーの一覧の表示を実現するビューとなります。より具体的には、UserList
は User
のインスタンスの一覧を表示します。
この ListView
に関しては下記ページで詳細を解説していますので、各クラス変数やメソッドの意味合いに関しては下記ページをご参照いただければと思います。
この UserList
は LoginRequiredMixin
を継承している点がポイントで、この LoginRequiredMixin
の継承により UserList
に対応する URL へのアクセスは非ログインユーザーからは禁止されることになります。より具体的には、非ログインユーザーが UserList
に対応する URL にアクセスしてきた際には強制的にログインページにリダイレクトされることになります(リダイレクトレスポンスが返却される)。
この “ログインページ” の URL は settings.py
での LOGIN_URL
の定義によって指定可能です。LOGIN_URL
を定義しなかった場合は、LOGIN_URL
にはデフォルトで /accounts/login/
が指定されるようになっています。今回は settings.py
での LOGIN_URL
を指定しないため /accounts/login/
にログインページが紐付けられるように urls.py
での URL とビューとのマッピングを行う必要があります。
さらに、LoginRequiredMixin
ではクラス変数 redirect_field_name
に 'next'
が定義されており、LoginRequiredMixin
を継承するビューに対応する URL へのアクセスが行われた際には、クエリパラメーター next
に “ログイン前にアクセスしようとしていた URL” として設定されることになります。
ただし、今回は UserList
側でクラス変数 redirect_field_name
の値を 'redirect'
で上書きしているため、クエリパラメーター redirect
に “ログイン前にアクセスしようとしていた URL” が設定されることになります。そして、UserLogin
でも クラス変数 redirect_field_name
の値に 'redirect'
を指定しているため、このクエリパラメーター redirect
への指定値を受け取ってログイン後に redirect
で指定される URL へのリダイレクトを行うことが可能となっています。
このように、クラス変数 redirect_field_name
を定義する際には、その指定値が LoginView
を継承するビューと LoginRequiredMixin
を継承するビューとで一致させておく必要があります(後述で説明するテンプレートファイルに関しても参照する変数名等を一致させておく必要があります)。まぁ、クラス変数 redirect_field_name
を定義しなかった場合の redirect_field_name
のデフォルト値は両方のクラスで 'next'
となっており、わざわざ変更しなければ redirect_field_name
への指定値が不一致となることはありません(今回はあえて変更する例を示しています)。
ビューと URL とのマッピング
次は views.py
で定義したビューと URL とのマッピングを行なっていきます。
まず、loginviewproject
フォルダの下にある urls.py
を下記のように変更してください。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')),
]
続いて、accounts
フォルダの下に urls.py
を新規作成し、中身を下記のように変更してください。
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.UserLogin.as_view(), name='login'),
path('logout/', views.UserLogout.as_view(), name='logout'),
path('register/', views.UserRegistration.as_view(), name='register'),
path('list/', views.UserList.as_view(), name='list'),
]
テンプレートの作成
次はテンプレートファイルを作成していきます。
最初にテンプレートファイルを設置するのに必要となるフォルダを準備しておきましょう。まずアプリフォルダ(accounts
フォルダ)の中に templates
フォルダを作成してください。次に、その templates
フォルダの中に accounts
フォルダを作成します。これでフォルダの準備は完了です。
今回 views.py
で定義した各種ビューではクラス変数 template_name
を定義して利用するテンプレートファイルのパスを指定するようにしているため、その指定したパスにテンプレートファイルを作成していきます。
user_login.html
まずは UserLogin
が利用するテンプレートファイルとして user_login.html
を用意していきます。先ほど作成した accounts
フォルダの中に user_login.html
を新規作成し、中身を下記のように変更してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of LoginView</title>
</head>
<body>
<main>
<h2>ログイン</h2>
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<input type="hidden" name="redirect" value="{{ redirect }}">
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
</main>
</body>
</html>
基本的にはフォームを表示するだけのテンプレートファイルになります。ただし、next へのリダイレクト で説明したように、クエリパラメーターで指定される URL も含めてフォームから送信されるように form
タグの中に input
タグを追加しています。今回の例ではビューでのクラス変数の定義によって “ログイン前にアクセスしようとしていた URL” を指定するクエリパラメーターの変数名は redirect
になっていることに注意してください。
user_form.html
続いて、UserRegistration
が利用するテンプレートファイルとして user_form.html
を用意します。先ほど作成した accounts
フォルダの中に user_form.html
を新規作成し、中身を下記のように変更してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of CreateView</title>
</head>
<body>
<main>
<h2>ユーザーの登録</h2>
<form action="{% url 'register' %}" method="post">
{% csrf_token %}
<table>{{ form.as_table }}</table>
<p><input type="submit" value="送信"></p>
</form>
</main>
</body>
</html>
user_list.html
最後に、UserList
が利用するテンプレートファイルとして user_list.html
を用意します。先ほど作成した accounts
フォルダの中に user_list.html
を新規作成し、中身を下記のように変更してください。
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Example of DetailView</title>
</head>
<body>
<main>
<h2>ユーザー一覧</h2>
<table>
<thead>
<tr>
<th>ID</th><th>ユーザー名</th>
</tr>
</thead>
<tbody>
{% for object in object_list %}
<tr>
<td>{{ object.id }}</td>
<td>{{ object.username }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</main>
</body>
</html>
スポンサーリンク
リダイレクト先の設定
最後に、settings.py
を変更してログイン後のリダイレクト先の URL とログアウト後のリダイレクト先の URL の指定を行なっていきます。
前者に関しては settings.py
で LOGIN_REDIRECT_URL
を定義することで、後者に関しては settings.py
で LOGOUT_REDIRECT_URL
を定義することで、それぞれを指定することが可能です。
また、前者に関しては、ログインページを表示するための GET
リクエスト時にクエリパラメーターで redirect
が指定されていない場合のリダイレクト先の URL となります。これらが指定されている場合はクエリパラメーター redirect
で指定される URL がログイン後のリダイレクト先の URL となります。
もう少し細かく説明すると、クエリパラメーターで redirect
が指定されていたとしても、POST
リクエスト時に送信されてくるデータに redirect
フィールドが存在しない場合はログイン後に LOGIN_REDIRECT_URL
で指定される URL へのリダイレクトが行われることになります
ただし、今回はクエリパラメーターで redirect
が指定された場合には必ず POST
リクエスト時に送信されてくるデータにも redirect
フィールドが追加されるようにテンプレートファイル等を作成しているため、クエリパラメーターで redirect
が指定されれば redirect
で指定される URL へのリダイレクトが行われるようになっています
今回は、下記を settings.py
に追記することで2つのリダイレクト先の指定を行うようにしたいと思います。追記場所は settings.py
の一番下で良いです。
LOGIN_REDIRECT_URL = '/accounts/register/'
LOGOUT_REDIRECT_URL = '/accounts/login/'
これにより、クエリパラメーターで redirect
が指定されていない場合はログイン後に /accounts/register/
にリダイレクトされてユーザーの新規登録ページ(新規登録フォーム)が表示されることになります。またログアウト後には /accounts/login/
にリダイレクトされてログインページ(ログインフォーム)が表示されることになります。
動作確認
最後に、ここまで作成してきたアプリの動作確認を行なっていきたいと思います。
開発用ウェブサーバーの起動
まず manage.py
が存在するフォルダで下記コマンドを実行します。
% python manage.py runserver
これにより、開発用ウェブサーバーが起動しますので、ウェブブラウザから作成したアプリのページを表示することが可能となります。
非ログインユーザーがアクセスできないことの確認
続いて下記 URL をウェブブラウザで表示してみてください。
http://localhost:8000/accounts/list/
この URL は、元々 urls.py
で UserList
に紐づけられている URL になります。なので、本来であれば UserList
によってユーザーの一覧ページが表示されるはずですが、現状は非ログイン状態であるため強制的にリダイレクトが行われることになります。
そして、このリダイレクトは UserList
が継承している LoginRequiredMixin
によって実施され、リダイレクト先は settings.py
で LOGIN_URL
に指定される URL となります。ですが、今回は settings.py
で LOGIN_URL
は定義していないため、デフォルト設定の /accounts/login/
にリダイレクトされることになります。そして、この URL は UserLogin
に紐づけられている URL であるため、結果としてログインページが表示されることになります。
このように、LoginRequiredMixin
を継承するビューを定義することで、非ログイン状態のユーザーのアクセスを拒否することが簡単に実現できます。
ユーザーの新規登録(ユーザーログイン)
現在ログインページが表示されているため、ここでログインを行えば先ほど表示しようとした /accounts/list/
も表示できるようになります。ですが、ログインを行うためには User
のインスタンスの新規登録が必要です。そのために、次は下記 URL をウェブブラウザで開いてください。
http://localhost:8000/accounts/register/
すると、下図のようなユーザーの新規登録フォームが表示されるはずです。これは UserRegistration
によって表示されるページとなります。
このフォームでユーザー名とパスワード(さらには確認用のパスワード)を入力して 送信
ボタンをクリックしてください。パスワードは8文字以上などの制限があるので注意してください。
これにより、ユーザーの新規登録が行われ、User
のインスタンスがレコードとしてデータベースに保存されることになります。さらに、ユーザーの新規登録後に自動的に /accounts/list/
にリダイレクトされてユーザー一覧が表示されるはずです(まだユーザーは一人しかいませんが…)。
ここまでの操作によって、LoginRequiredMixin
を継承するクラスによって表示するページが非ログイン状態の際には表示できないこと、ログイン中であれば通常通り表示できることが確認できたと思います。ログイン機能を搭載するのは、非ログインユーザーからのアクセスを禁止することを目的とすることも多いため、この LoginRequiredMixin
については覚えておくと良いと思います。
ログアウト
続いて、ウェブブラウザで下記 URL を開いてください。
http://localhost:8000/accounts/logout/
この URL をウェブブラウザで開くとログアウトが行われます。そして、settings.py
で LOGOUT_REDIRECT_URL
に /accounts/login/
を指定しているため、ログインページが表示されることになります。
今回はログインは行わず、再度下記 URL をウェブブラウザで開いてみてください。
http://localhost:8000/accounts/list/
すると、最初に上記 URL をウェブブラウザで表示した時と同様にログインページにリダイレクトされるはずです。これは、先ほどの /accounts/logout/
へのアクセスによってログアウトが実行され、非ログイン状態に戻ってしまったからになります。前述の通り、このリダイレクトは LoginRequiredMixin
によって実施されます。
ログイン(クエリパラメーター redirect
有りの場合)
ここで注目していただきたいのがリダイレクトされた先の URL となります。ということで、ウェブブラウザの URL バーを確認してみてください。表示される URL は下記のようなものになっており、クエリパラメーター redirect
が指定されるようになっているはずです。
このようにリダイレクト先の URL にクエリパラメーター redirect
が付加されるようになっているのは UserList
が LoginRequiredMixin
を継承しており、さらにクラス変数 redirect_field_name
に 'redirect'
を指定しているからになります。そして、redirec
の値は /accounts/list/
であり、これは非ログイン状態でアクセスしようとしたページの URL のルートパスになります。
また、表示されているページのソースを確認してみれば分かると思いますが、フォーム要素部分の HTML は下記のようになっており、name="redirect"
および value="/accounts/list/"
が指定された input
タグが存在することになります。このため、送信
ボタンがクリックされた際には "redirect" : "/accounts/list/"
という要素が追加された辞書(のような)データが送信されることになります。
<form action="/accounts/login/" method="post">
<input type="hidden" name="csrfmiddlewaretoken" value="略">
<input type="hidden" name="redirect" value="/accounts/list/">
〜略〜
ということで、次は実際にログインを行なってみましょう!
先ほどユーザーを新規登録したはずですので、その登録した username
と password
をフォームの各フィールドに入力して 送信
ボタンをクリックしてください。
username
と password
が正しければ、ログインが行われた後に自動的にユーザー一覧の表示ページに遷移するはずです。
このページはログイン中でないと表示できないため、このページが表示されたことでログインが正常に実施されたことが確認できたことになります。また、このページに遷移したのはフォームから送信されたデータにおける redirect
フィールドが /accounts/list/
であるためになります。このように、クエリパラメーターで指定された URL のルートパスをフォームを介して LoginView
のサブクラスに渡すことで、ログイン後にクエリパラメーターで指定された URL へのリダイレクトが可能となります。
ログイン(クエリパラメーター redirect
無しの場合)
それに対し、クエリパラメーターで URL のルートパスが指定されなかった場合は settings.py
の LOGIN_REDIRECT_URL
で指定される URL へのリダイレクトが行われることになります。
これについても確認しておきましょう!
まず、下記 URL をウェブブラウザで開いてログアウトを実施してください。
http://localhost:8000/accounts/logout/
すると、ログアウト後に自動的に下記 URL へのリダイレクトが行われることになります。
http://localhost:8000/accounts/login/
この場合、非ログイン状態のユーザーでアクセス禁止されていたページへのアクセスを行なったわけではなく、直接ログインページにアクセスされたことになるため、ウェブブラウザの URL バーに表示される URL にはクエリパラメーターが存在しないことになります。
続いて、先ほど同様に username
と password
を入力して 送信
ボタンをクリックしてください。今度はログイン後に下記 URL にリダイレクトされてユーザーの新規登録ページに自動的に遷移するはずです。
http://localhost:8000/accounts/register/
先ほどとは異なるページへのリダイレクトが行われていることが確認できると思います。そして、この違いはクエリパラメーター redirect
の存在の有無によるものとなります。前述の通り、URL にクエリパラメーター redirect
が存在する場合は redirect
で指定される URL にリダイレクトされますが、存在しない場合は settings.py
の LOGIN_REDIRECT_URL
にリダイレクトされることになります。今回、LOGIN_REDIRECT_URL
には /accounts/register/
を指定しているため、上記 URL にリダイレクトされたことになります。
ログイン状態でのログインページの表示
最後に、ログイン状態でログインページを表示しようとした時の動作について確認しておきたいと思います。
現在はログイン状態のはずなので、その状態で再度下記 URL をウェブブラウザで開いてみてください。
http://localhost:8000/accounts/login/
すると、ログインページが表示されるのではなく、またユーザーの新規登録ページが表示されることになるはずです。これは、UserLogin
でクラス変数 redirect_authenticated_user
を定義して True
を指定しているためで、この場合はログイン状態のユーザーがログインページを表示しようとすると他の URL へのリダイレクトが行われることになります。そして、このリダイレクト先は LoginView
のサブクラスのクラス変数 next_page
を定義している場合は next_page
に対応する URL、定義していない場合は settings.py
での LOGIN_REDIRECT_URL
に指定される URL となります。
ログイン状態でもログインページを表示できるようにしたいのであれば、クラス変数 redirect_authenticated_user
の定義を削除してやれば良いことになります。
ここまで説明した内容から感じ取ってもらえたと思いますが、LoginView
を使えば簡単にログイン機能をウェブアプリに搭載することが可能となります。ですが、色んな箇所でリダイレクトが行われるため、リダイレクトには関してはちょっとややこしいです。この辺りに関しては自身でウェブアプリを開発し、リダイレクトに関して色々試行して慣れていっていただければと思います。
まとめ
このページでは、LoginView
および LoginView
を継承したクラスベースビューの作り方について解説しました!
LoginView
はログインを扱うビューを実現するための View のサブクラス
であり、このクラスを継承するビューを定義することで、ウェブアプリにログイン機能を搭載することが可能となります。
LoginView
は FormView
のサブクラスであり、既にログインに特化する形で作り込まれた View のサブクラス
となります。したがって、他の View のサブクラス
に比べるとカスタマイズ要素は少なめです。
なので、LoginView
のサブクラスを定義するだけでログイン自体は簡単に実現することができます。ただし、他のビューのアクセス制限を設ける必要があったり、リダイレクトに関してはややこしい点もあったりしますので、この辺りがウェブアプリにログイン機能を搭載する際のポイントになると思います。
様々なウェブアプリでログイン機能が搭載されていることからも分かるように、ログイン機能が実現できるようになれば、開発可能なウェブアプリの幅が一気に広がります。その分ウェブアプリ開発も楽しくなると思いますので、是非 LoginView
を利用したビューの作り方については覚えておいてください!
また、このサイトでは他の View のサブクラス
についても説明していますので、他のページも是非読んでみてください!