【Django】ログイン機能の実現方法(クラスベースビュー編)

Djangoでクラスベースビューでログインを実現する方法の解説ページアイキャッチ

このページでは、Django での「ログイン機能」の実現方法について解説していきたいと思います!

実は、このサイトでは既に、Django でのログイン機能の実現方法を下記ページで解説しています。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

ただ、上記ページではログイン機能を関数ベースビューで実現してきました。関数を自作してログインを実現する形になるため、自作を行う分手間がかかります…。

それに対し、このページではログイン機能を実現する際の View をクラスベースビューとして実現していきます。Django に既存で用意されているクラス(TemplateViewCreateViewLoginViewLogoutView)を継承して View を作成していくことでサクッとお手軽にログイン機能を実現することが出来ます。

といっても、結局ログイン機能を実現する際に必要になるアプリの処理・動作は上記ページで解説しているものと変わりません。具体的にどういった処理が必要であるかについては上記ページで解説していますし、理解を深めるためにも事前に上記ページを読んでいただくことをオススメします。

また、基本的には、このページでは上記ページで紹介したソースコードの views.py を関数ベースからクラスベースビューに変更していく形で、クラスベースビューでのログイン機能の実現手順を解説していきます。

そのため、上記ページを参照しながら解説を進めていきますので、その点についてもご容赦いただければと思います。

事前準備

それでは、クラスベースビューによりログイン機能を実現していきたいと思います。

ただ、アプリの大枠としては下記ページで解説しているものと全く同じになりますので、まずは下記ページの 事前準備(プロジェクトやアプリの作成など) の節の内容に従い、プロジェクトやアプリの作成等を行なっていただければと思います。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【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 を次のように変更することで、上記のような処理を「クラスベースビュー」で実現することが出来ます。

ログインを実現するView
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でのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

なので、ユーザーアカウント登録で必要な処理は CreateView を継承してクラスを定義し、それをユーザーアカウント登録に対する View として利用してやるだけで実現することが出来ます。

また、CreateView のような Django に既存で用意されている View クラスを継承してクラスを作成する際には、クラス変数の定義によって動作をカスタマイズすることが出来ます。上記においては次の3つを設定しており、これにより ログイン機能実現用のスクリプト で紹介した login_app/views.pysignup_view 関数を利用した時と同様の動作が行われるようにしています。

  • template_name:GET 時に表示を行うページのテンプレートファイル
  • form_class:テンプレートに組み込むフォームのクラス
  • success_url:レコード保存成功時のリダイレクト先のパスや URL

また、メソッドのオーバーライドを行なってカスタマイズも行うことも可能で、上記では form_valid メソッドのオーバーライドを行なっています。

form_valid はフォームから送信されてきたデータ(今回の場合はユーザー名・メールアドレス・パスワード・確認用パスワード)が「妥当である」と判断された場合に実行されるメソッドになります。例えばパスワードと確認用パスワードが異なる場合などは、妥当でないと判断されて form_valid メソッドは実行されません。

通常の CreateView における form_valid メソッドでは、基本的にデータベースへのレコードの保存しか行われません。

ただ、今回はフォームから送信されてきたデータが妥当である際にはデータベースにレコードを保存するだけでなく(つまりユーザーアカウント登録を行うだけでなく)、ログインまで実行させるようにしたかったため、form_valid メソッドをオーバーライドしてデータベースへのレコード保存後にログインを行うようにしています。

具体的には、まず super().form_valid(form) で CreateViewform_valid メソッドを実行し、この中でレコードの保存を行なっています。

MySignupView では form_class = SignupForm を指定しており、さらに SignupFormUser モデルに対する ModelForm なので、super().form_valid(form) を実行することで User のインスタンスがレコードとして保存されることになります。

MEMO

SignupForm については ユーザーアカウント登録用の Form の作成 で解説を行なっています

そして、この保存によってユーザーアカウントが登録されることになります(ユーザーの情報がデータベースに保存される)。

さらに、その後に login 関数を実行して登録されたユーザーでログインを行い、最後に super().form_valid(form) の返却値を return するようにしています。

login 関数実行時にポイントになるのが、データベースに保存された User のインスタンスの取得が必要である点になります。login 関数を実行する際には、第2引数としてログインさせる User のインスタンスを指定する必要があります。

CreateViewform_valid メソッドにおいては、メソッド内で保存したモデルのインスタンスが self.object にセットされるようになっています。ですので、上記の form_valid メソッドのように self.objectlogin 関数の第2引数に指定してやれば、login 関数の第2引数にログインさせる User のインスタンスを指定することが出来ます。

そしてその状態で login 関数を実行することで、ユーザーアカウント登録を行なったユーザーのログインを実現しています。

以上のような実装によって、ログイン機能実現用のスクリプト で紹介した login_app/views.pysignup_view 関数を利用した時と同様のユーザーアカウント登録を行う MySignupView を定義することが出来ます。

ログイン

続いてログインについて解説していきます。

上記の login_app/views.py において、ログインを実現するのは MyLoginView クラスとなります。

MyLoginView クラスは LoginView のサブクラスであり、LoginView は Django に用意されているログインを担当するクラスです。

まさに、MyLoginView クラスで実現しようとしているログインそのものを LoginView が担当してくれているので、LoginView のサブクラスとしてクラスを定義してやるだけで、ログインが実現できることになります。

ただ、ログインページ表示時の Template と、表示する Form に関しては設定が必要なため、上記の MyLoginView クラスのように template_nameform_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.usercontext['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 関数と同様の動作をクラスで実現できることになります。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

ログイン後のリダイレクト

また、これも @login_required 同様で、LoginRequiredMixin によってリダイレクトが行われた際には、リダイレクト先の URL に対してクエリストリングとして next が設定されるようになります。

クエリストリングが吹かされる様子

さらに、この next にはリダイレクト元のページ(元々アクセスしようとしていたページ)のパスが設定されますので、この next のパラメータを利用することで、ログイン後のリダイレクト先を「元々アクセスしようとしていたページ」とすることが出来ます。

そして LoginView は、この next のパラメータを利用し、ログインに成功した際には next で指定されるパスにリダイレクトを行うように作られています。

ただし、実際にリダイレクトを行うのは POST 時(ログインに必要なユーザー名やパスワードが送信されてきた時)なので、POST 時に next のパラメータを LoginView に渡せるようにする必要があります。

これは、ログインページに使用する Template のフォームにおいて、下記のように namenext である input タグを追加し、フォーム送信時にユーザー名やパスワードに加えて next のパラメータが送信されるようにすることで、実現することが出来ます。

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>

これによって、ユーザーが ログイン ボタンを押してフォームを送信する際に LoginViewnext のパラメータが渡されるようになり、ログイン後に next に指定されているパス(元々アクセスしようとしていたページ)にリダイレクトされるようになります。

念のため説明しておくと、下記ページの ログイン機能実現用のスクリプト で紹介している login.html は、既に上記のような input タグの追加は行っていますので、コピペして login.html を作成してくださった方は、ここでの login.html の修正は不要です。

Djangoでのログイン機能の実現方法解説ページアイキャッチ【Django】ログイン機能の実現方法(関数ベースビュー編)

また、上記のリダイレクト先の解説は、ログインページが表示された際の URL に next のパラメータが設定されている場合の話であり、next のパラメータが設定されていない場合は、デフォルトでは '/accounts/profile/' というパスにリダイレクトされるようになっています。

このリダイレクト先を変えたい場合は、次に説明する settings.py の設定が必要になります。

スポンサーリンク

settings.py の設定

ここまでが、views.py に対する解説になります。

ここからは、views.py に定義した View クラスをうまく動作させるために login_project/settings.pylogin_app/urls.py を設定していきたいと思います。

まず、login_project/settings.py の設定を行なっていきます。

先ほど述べたように、next が設定されていない時のログイン後のリダイレクト先のデフォルト設定は /accounts/profile/ となっています。

これだと都合が悪い場合も多いので、このリダイレクト先の変更方法について解説しておきます。

このリダイレクト先の設定は、settings.py に LOGIN_REDIRECT_URL を指定することで変更することが出来ます。

今回は、next が設定されていない時のログイン後のリダイレクト先として /login_app/user/ を設定したいため、login_project/settings.py に下記の1行を追記します。

settings.pyの設定
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 で定義したクラスの対応づけを行います。

urls.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 における「ログイン機能」のクラスベースビューでの実現方法について解説しました!

Django に標準で用意されているクラスを継承してクラス View を作成することで、より簡単にウェブアプリにログイン機能やログイン機能に関連する動作を実現することが可能です。

特にログインやログアウトに関しては LoginViewLogoutView を継承させるだけで機能を実現することが可能ですし、LoginRequiredMixin を継承させるだけで未ログインユーザーのアクセス禁止も実現することが可能です。

ログイン機能の実現方法を知っておけば、開発できるウェブアプリの幅が大きく広がりますので、是非今回紹介したクラスなどは覚えておいてください!

同じカテゴリのページ一覧を表示

コメントを残す

メールアドレスが公開されることはありません。