このページでは、Django での「ログイン機能」の実現方法について解説していきたいと思います!
実は、このサイトでは既に、Django でのログイン機能の実現方法を下記ページで解説しています。
【Django】ログイン機能の実現方法(関数ベースビュー編)ただ、上記ページではログイン機能を関数ベースビューで実現してきました。関数を自作してログインを実現する形になるため、自作を行う分手間がかかります…。
それに対し、このページではログイン機能を実現する際の View をクラスベースビューとして実現していきます。Django に既存で用意されているクラス(TemplateView
・CreateView
・LoginView
・LogoutView
)を継承して View を作成していくことでサクッとお手軽にログイン機能を実現することが出来ます。
といっても、結局ログイン機能を実現する際に必要になるアプリの処理・動作は上記ページで解説しているものと変わりません。具体的にどういった処理が必要であるかについては上記ページで解説していますし、理解を深めるためにも事前に上記ページを読んでいただくことをオススメします。
また、基本的には、このページでは上記ページで紹介したソースコードの views.py
を関数ベースからクラスベースビューに変更していく形で、クラスベースビューでのログイン機能の実現手順を解説していきます。
そのため、上記ページを参照しながら解説を進めていきますので、その点についてもご容赦いただければと思います。
Contents
事前準備
それでは、クラスベースビューによりログイン機能を実現していきたいと思います。
ただ、アプリの大枠としては下記ページで解説しているものと全く同じになりますので、まずは下記ページの 事前準備(プロジェクトやアプリの作成など) の節の内容に従い、プロジェクトやアプリの作成等を行なっていただければと思います。
【Django】ログイン機能の実現方法(関数ベースビュー編)また、使用する forms.py
やテンプレートに関しては上記ページの ログイン機能実現用のスクリプト と全く同じものを利用します。
そのため、上記ページの ログイン機能実現用のスクリプト と同じ forms.py
とテンプレートファイル群を用意しておいていただければと思います。
ここからは、上記ページで紹介しているスクリプトから次の3つのファイルを変更していくことで、ログイン機能をクラスベースの View で実現していきます。
login_app/views.py
login_project/settings.py
login_app/urls.py
views.py
の作成
では、まずは View の作成を行なっていきたいと思います。
【Django】ログイン機能の実現方法(View関数自作編) でも解説していますが、ウェブアプリでログインを機能させるためには下記のような処理が必要になります。
- ユーザーアカウントの登録
- ログイン
- ログアウト
- ログインユーザーに応じたページ表示
- 未ログインユーザーからのアクセス禁止
- ログイン後のリダイレクト
【Django】ログイン機能の実現方法(View関数自作編) のページでは上記を関数ベースで実現しましたが、login_app/views.py
を次のように変更することで、上記のような処理を「クラスベースビュー」で実現することが出来ます。
from .forms import SignupForm, LoginForm
from django.contrib.auth import login
from django.contrib.auth.models import User
from django.contrib.auth.views import LoginView, LogoutView
from django.views.generic import TemplateView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
class MySignupView(CreateView):
template_name = 'login_app/signup.html'
form_class = SignupForm
success_url = '/login_app/user/'
def form_valid(self, form):
result = super().form_valid(form)
user = self.object
login(self.request, user)
return result
class MyLoginView(LoginView):
template_name = 'login_app/login.html'
form_class = LoginForm
class MyLogoutView(LogoutView):
template_name = 'login_app/logout.html'
class MyUserView(LoginRequiredMixin, TemplateView):
template_name = 'login_app/user.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user'] = self.request.user
return context
class MyOtherView(LoginRequiredMixin, TemplateView):
template_name = 'login_app/other.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['users'] = User.objects.exclude(username=self.request.user.username)
return context
ログイン機能実現用のスクリプト で紹介した login_app/views.py
に比べると、かなりスッキリしたソースコードに仕上がっていることを確認できると思います。
ここからは、上記の login_app/views.py
によって、先程も挙げた次の6つの処理をどのようにして実現しているのかについて解説していきたいと思います。
- ユーザーアカウントの登録
- ログイン
- ログアウト
- ログインユーザーに応じたページ表示
- 未ログインユーザーからのアクセス禁止
- ログイン後のリダイレクト
スポンサーリンク
ユーザーアカウントの登録
ユーザーアカウントの登録を実現するのは MySignupView
クラスとなります。
このクラスは CreateView
のサブクラスであり、CreateView
はデータベースへのレコードの新規作成(新規保存)を担当するクラスとなります。
下記ページでも解説しているとおり、ユーザーアカウント登録は、ウェブブラウザから送信されてきたユーザーの情報(ユーザー名やパスワードなど)をデータベースにレコードとして保存することで実現できます。
【Django】ログイン機能の実現方法(関数ベースビュー編)なので、ユーザーアカウント登録で必要な処理は CreateView
を継承してクラスを定義し、それをユーザーアカウント登録に対する View として利用してやるだけで実現することが出来ます。
また、CreateView
のような Django に既存で用意されている View クラスを継承してクラスを作成する際には、クラス変数の定義によって動作をカスタマイズすることが出来ます。上記においては次の3つを設定しており、これにより ログイン機能実現用のスクリプト で紹介した login_app/views.py
の signup_view
関数を利用した時と同様の動作が行われるようにしています。
template_name
:GET 時に表示を行うページのテンプレートファイルform_class
:テンプレートに組み込むフォームのクラスsuccess_url
:レコード保存成功時のリダイレクト先のパスや URL
また、メソッドのオーバーライドを行なってカスタマイズも行うことも可能で、上記では form_valid
メソッドのオーバーライドを行なっています。
form_valid
はフォームから送信されてきたデータ(今回の場合はユーザー名・メールアドレス・パスワード・確認用パスワード)が「妥当である」と判断された場合に実行されるメソッドになります。例えばパスワードと確認用パスワードが異なる場合などは、妥当でないと判断されて form_valid
メソッドは実行されません。
通常の CreateView
における form_valid
メソッドでは、基本的にデータベースへのレコードの保存しか行われません。
ただ、今回はフォームから送信されてきたデータが妥当である際にはデータベースにレコードを保存するだけでなく(つまりユーザーアカウント登録を行うだけでなく)、ログインまで実行させるようにしたかったため、form_valid
メソッドをオーバーライドしてデータベースへのレコード保存後にログインを行うようにしています。
具体的には、まず super().form_valid(form)
で CreateView
の form_valid
メソッドを実行し、この中でレコードの保存を行なっています。
MySignupView
では form_class = SignupForm
を指定しており、さらに SignupForm
は User
モデルに対する ModelForm
なので、super().form_valid(form)
を実行することで User
のインスタンスがレコードとして保存されることになります。
SignupForm
については ユーザーアカウント登録用の Form の作成 で解説を行なっています
そして、この保存によってユーザーアカウントが登録されることになります(ユーザーの情報がデータベースに保存される)。
さらに、その後に login
関数を実行して登録されたユーザーでログインを行い、最後に super().form_valid(form)
の返却値を return
するようにしています。
login
関数実行時にポイントになるのが、データベースに保存された User
のインスタンスの取得が必要である点になります。login
関数を実行する際には、第2引数としてログインさせる User
のインスタンスを指定する必要があります。
CreateView
の form_valid
メソッドにおいては、メソッド内で保存したモデルのインスタンスが self.object
にセットされるようになっています。ですので、上記の form_valid
メソッドのように self.object
を login
関数の第2引数に指定してやれば、login
関数の第2引数にログインさせる User
のインスタンスを指定することが出来ます。
そしてその状態で login
関数を実行することで、ユーザーアカウント登録を行なったユーザーのログインを実現しています。
以上のような実装によって、ログイン機能実現用のスクリプト で紹介した login_app/views.py
の signup_view
関数を利用した時と同様のユーザーアカウント登録を行う MySignupView
を定義することが出来ます。
ログイン
続いてログインについて解説していきます。
上記の login_app/views.py
において、ログインを実現するのは MyLoginView
クラスとなります。
MyLoginView
クラスは LoginView
のサブクラスであり、LoginView
は Django に用意されているログインを担当するクラスです。
まさに、MyLoginView
クラスで実現しようとしているログインそのものを LoginView
が担当してくれているので、LoginView
のサブクラスとしてクラスを定義してやるだけで、ログインが実現できることになります。
ただ、ログインページ表示時の Template と、表示する Form に関しては設定が必要なため、上記の MyLoginView
クラスのように template_name
と form_class
指定を行うようにしています。
ログアウト
次はログアウトについて解説していきます。
上記の login_app/views.py
において、ログアウトを実現するのは MyLogoutView
クラスとなります。
MyLogoutView
クラスは LogoutView
のサブクラスであり、LogoutView
は Django に用意されているログアウトを担当するクラスです。
ログアウトに関しても、LogoutView
のサブクラスとしてクラスを定義するだけで実現可能であり、あとはログアウトページで表示する Template をクラス変数 template_name
で指定してやれば良いだけです。
スポンサーリンク
ログインユーザーに応じたページ表示
ログインユーザーに応じたページの表示を実現しているのは MyUserView
クラスと MyOtherView
クラスになります。
前者はログインユーザーの情報を表示し、後者はログインユーザー以外の情報を表示することを担当するクラスとなっています。
これらは TemplateView
を継承して作成しており(LoginRequiredMixin
については後述で解説)、template_name
に表示用の Template を指定しておくだけで、その Template を利用したページ表示を実現することが出来ます。
ただし、MyUserView
クラスの場合はログインユーザーを、MyOtherView
クラスの場合はログインユーザー以外の queryset
を Template に渡せるようにするため、get_context_data
メソッドをオーバーライドし、get_context_data
メソッドの中で Template に渡すデータ(context
)の設定を行うようにしています。
具体的には、MyUserView
クラスの場合はログインユーザーがセットされている self.request.user
を context['user']
に、MyOtherView
クラスの場合はログインユーザー以外を User.objects.exclude
で取得し、それを context['users']
にそれぞれ設定するようにしています。
未ログインユーザーからのアクセス禁止
また、MyUserView
クラスと MyOtherView
クラスは LoginRequiredMixin
も継承する形で作成しています。
この LoginRequiredMixin
こそが、未ログインユーザーからのアクセスを禁止するクラスとなります。
この LoginRequiredMixin
を継承したクラスをクラス View として利用した場合、未ログインユーザーはその View にはアクセスできなくなり、アクセス時には特定のページにリダイレクトされるようになります。
この “特定のページ” とは、settings.py
において LOGIN_URL
で設定される URL(パス)のページとなります(settings.py
で設定されていない場合は '/accounts/login/'
)。
つまり、LoginRequiredMixin
を継承してクラスを作成することで、下記ページで紹介した @login_required
を設定した View 関数と同様の動作をクラスで実現できることになります。
ログイン後のリダイレクト
また、これも @login_required
同様で、LoginRequiredMixin
によってリダイレクトが行われた際には、リダイレクト先の URL に対してクエリストリングとして next
が設定されるようになります。
さらに、この next
にはリダイレクト元のページ(元々アクセスしようとしていたページ)のパスが設定されますので、この next
のパラメータを利用することで、ログイン後のリダイレクト先を「元々アクセスしようとしていたページ」とすることが出来ます。
そして LoginView
は、この next
のパラメータを利用し、ログインに成功した際には next
で指定されるパスにリダイレクトを行うように作られています。
ただし、実際にリダイレクトを行うのは POST 時(ログインに必要なユーザー名やパスワードが送信されてきた時)なので、POST 時に next
のパラメータを LoginView
に渡せるようにする必要があります。
これは、ログインページに使用する Template のフォームにおいて、下記のように name
が next
である input
タグを追加し、フォーム送信時にユーザー名やパスワードに加えて next
のパラメータが送信されるようにすることで、実現することが出来ます。
{% load static %}
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ログイン</title>
</head>
<body>
<h1>ログイン</h1>
<form action="{% url 'login'%}" method="post">
{% csrf_token %}
{{ form.as_p }}
<p><input type="hidden" name="next" value="{{next}}"></p>
<p><input type="submit" value="ログイン"></p>
</form>
</body>
</html>
これによって、ユーザーが ログイン
ボタンを押してフォームを送信する際に LoginView
に next
のパラメータが渡されるようになり、ログイン後に next
に指定されているパス(元々アクセスしようとしていたページ)にリダイレクトされるようになります。
念のため説明しておくと、下記ページの ログイン機能実現用のスクリプト で紹介している login.html
は、既に上記のような input
タグの追加は行っていますので、コピペして login.html
を作成してくださった方は、ここでの login.html
の修正は不要です。
また、上記のリダイレクト先の解説は、ログインページが表示された際の URL に next
のパラメータが設定されている場合の話であり、next
のパラメータが設定されていない場合は、デフォルトでは '/accounts/profile/'
というパスにリダイレクトされるようになっています。
このリダイレクト先を変えたい場合は、次に説明する settings.py
の設定が必要になります。
スポンサーリンク
settings.py
の設定
ここまでが、views.py
に対する解説になります。
ここからは、views.py
に定義した View クラスをうまく動作させるために login_project/settings.py
と login_app/urls.py
を設定していきたいと思います。
まず、login_project/settings.py
の設定を行なっていきます。
先ほど述べたように、next
が設定されていない時のログイン後のリダイレクト先のデフォルト設定は /accounts/profile/
となっています。
これだと都合が悪い場合も多いので、このリダイレクト先の変更方法について解説しておきます。
このリダイレクト先の設定は、settings.py
に LOGIN_REDIRECT_URL
を指定することで変更することが出来ます。
今回は、next
が設定されていない時のログイン後のリダイレクト先として /login_app/user/
を設定したいため、login_project/settings.py
に下記の1行を追記します。
LOGIN_REDIRECT_URL = '/login_app/user/'
これにより、next
が設定されていない時のログイン後のリダイレクト先が /login_app/user/
となります。
また、LoginRequiredMixin
によってリダイレクトが行われて next
が設定されている際には、next
で指定されるパス、つまり元々アクセスしようとしていたページがリダイレクト先となります。
urls.py
の設定
最後に login_app/urls.py
を設定すれば、クラスベースビューを利用したログイン機能実現の完了になります。
具体的には、login_app/urls.py
を下記のように変更し、URL(パス)と views.py
で定義したクラスの対応づけを行います。
from . import views
from django.urls import path
urlpatterns = [
path('signup/', views.MySignupView.as_view(), name='signup'),
path('login/', views.MyLoginView.as_view(), name='login'),
path('logout/', views.MyLogoutView.as_view(), name='logout'),
path('user/', views.MyUserView.as_view(), name='user'),
path('other/', views.MyOtherView.as_view(), name='other'),
]
上記によって各パス(URL)へのアクセスがあった際には、login_app/views.py
で定義したクラスが動作するようになります。
例えば /login_app/signup/
にアクセスがあった際には、login_app/views.py
で定義した MySignupView
のメソッドが実行され、ユーザーアカウント登録用のページ表示やユーザーアカウント登録の処理の実行が行われるようになります。
指定するのがクラス名そのものではなく、クラス名.as_view()
であることに注意してください。
動作確認
以上により、クラスベースビューによってログイン機能が実現できたことになります。
最後に動作確認を行なっておきましょう!
まずは、下記コマンドを実行して Django 開発用ウェブサーバーを起動してください。
% python manage.py runserver
続いて、下記 URL をウェブブラウザで開いてみてください。
http://localhost:8000/login_app/signup/
すると、下の図のようなユーザーアカウント登録画面が表示されるはずです。
ここに、ユーザー名・メールアドレス・パスワード・確認用パスワードを入力して 登録
ボタンを押せば、ユーザーアカウントが作成され、さらにそのユーザーアカウントでログインが行われます。そして、下の図のようなページにリダイレクトされるはずです。
このページにはログインユーザーの情報が表示されており、ログインしているユーザーによって表示内容が変化します。
再度下記 URL にアクセスし、先ほどとは異なるユーザーアカウントを登録してみてください。
http://localhost:8000/login_app/signup/
登録が完了すれば先ほど同様にログインユーザーの情報が表示されるページにリダイレクトされると思いますが、ログインしているユーザーが変わったため、表示される内容も変化していることが確認できるはずです。
さらに、ページ内の 他のユーザーの情報
リンクをクリックしてみてください。そうすると、ログインユーザー以外のユーザーの情報が表示されるはずです。
続いて、ページ内の ログアウト
リンクをクリックしてログアウトを行いましょう!
そして、ログアウト後に今度は下記 URL をウェブブラウザで表示してみてください。
http://localhost:8000/login_app/other/
上記 URL は、先ほど閲覧したログインユーザー以外のユーザーの情報を表示するページのものなのですが、まだログインをしていないためリダイレクトが行われてログインページが表示されるはずです。
次は、先ほど作成したユーザーアカウントを用いてログインを行なってみてください。
ログインに成功すれば、元々アクセスしようとしていたログインユーザー以外のユーザーの情報を表示するページにリダイレクトされることが確認できるはずです。
これらの動作結果より、今回作成したスクリプトによって下記の6つの処理や動作を実現することが出来ていることを確認していただけたと思います。
- ユーザーアカウントの登録
- ログイン
- ログアウト
- ログインユーザーに応じたページ表示
- 未ログインユーザーからのアクセス禁止
- ログイン後のリダイレクト
下記ページを読んでくださった方であれば理解していただけると思いますが、基本的には下記ページの ログイン機能実現用のスクリプト で紹介したスクリプトと同様の動作が実現できているはずです(細かい動作の違いなどはあるかもしれませんが)。
【Django】ログイン機能の実現方法(関数ベースビュー編)このように、ログイン機能に関しても関数ベースとクラスベース両方で実現することができます。
実現の簡単さはクラスベースの方が上だと思いますが、ログイン機能を実現する上で必要になる処理については関数ベースの方がイメージしやすく、理解もしやすいのではないかと思います。
もちろん単に機能を実現したいだけであればクラスベースで実装するので良いですが、動作の詳細をしっかり理解しておきたい場合は、まずは関数ベースで処理を考えてみても良いと思います。
スポンサーリンク
まとめ
このページでは、Django における「ログイン機能」のクラスベースビューでの実現方法について解説しました!
Django に標準で用意されているクラスを継承してクラス View を作成することで、より簡単にウェブアプリにログイン機能やログイン機能に関連する動作を実現することが可能です。
特にログインやログアウトに関しては LoginView
や LogoutView
を継承させるだけで機能を実現することが可能ですし、LoginRequiredMixin
を継承させるだけで未ログインユーザーのアクセス禁止も実現することが可能です。
ログイン機能の実現方法を知っておけば、開発できるウェブアプリの幅が大きく広がりますので、是非今回紹介したクラスなどは覚えておいてください!