\ ポイント最大11倍! /

【django-allauth】ビューロジックのカスタマイズ方法

  • django-allauthでビューロジックのカスタマイズがしたい!

このような方に向けて書きました。

django-allauthの標準のビューロジックはとても良くできていますが、要件によってはカスタマイズが必要なケースもあります。

本記事ではよく使うビューロジックの調整方法を解説します。

【django-allauth】ビューロジックのカスタマイズ

成功時のリダイレクト先を設定

クラス変数のsuccess_urlにURLパターンを指定することで、リダイレクト先の指定ができます。

以下はLoginViewの例です。

from allauth.account.views import LoginView
from django.urls import reverse_lazy


class CustomLoginView(LoginView):
    def get_success_url(self):
        # サインアップ成功後のリダイレクト先
        return reverse_lazy("home")

以下のビューについても、同じ方法でリダイレクト先の変更ができます。

  • SignupView
  • LoginView
  • PasswordChangeView
  • PasswordSetView
  • PasswordResetView
  • PasswordResetDoneView
  • PasswordResetFromKeyView
  • PasswordResetFromKeyDoneView
  • EmailView
  • ConfirmEmailView
  • EmailVerificationSentView

ログアウトビューの場合の変数名は next_page なので注意が必要です。

class CustomLogoutView(LogoutView):
    next_page = reverse_lazy("accounts:account_login")

    def post(self, request, *args, **kwargs):
        next_page = reverse_lazy("accounts:account_login")

ちなみに、このクラス変数を指定する方法は「リダイレクト先が固定されてしまう」というデメリットがあります。

そこで条件に応じてリダイレクトをしたい場合には、get_success_url()メソッドをオーバーライドします。

次のコードは「スーパーユーザー権限の有無」でリダイレクト先を変更した例です。

from allauth.account.views import LoginView
from django.urls import reverse_lazy


class CustomLoginView(LoginView):
    def get_success_url(self):
        if self.request.user.is_superuser:
            # 管理者用ダッシュボードへのリダイレクト
            return reverse_lazy("admin_dashboard")
        else:
            # 一般ユーザー用ダッシュボードへのリダイレクト
            return reverse_lazy("user_dashboard")  

このように、リダイレクト先の細かい調整が必要な場合にはオーバーライドで対応しましょう。

サインアップ後に自動的にログインさせる

デフォルトではサインアップ後にメールアドレス確認メールが送信されます。

基本的には「セキュリティ確保」や「誤入力の防止」のために、デフォルトの設定を採用すべき。

ところが、ユーザー登録後にログイン状態にしたい場合もあります。

実装にあたってはform_valid()メソッドにlogin()メソッドを追加して対応します。

from allauth.account.views import SignupView
from django.contrib.auth import login
from django.shortcuts import redirect


class CustomSignupView(SignupView):
    def form_valid(self, form):
        # ユーザーを保存し、登録
        response = super().form_valid(form)
        # ユーザーを自動的にログインさせる
        login(self.request, self.user)
        # リダイレクト
        return response

また、自動ログインさせる場合にはメール確認もスキップする必要があります。

settings.pyに次のコードを追加しましょう。

# メールの確認を無効化
ACCOUNT_EMAIL_VERIFICATION = "none"
# リダイレクト先を指定する場合
ACCOUNT_SIGNUP_REDIRECT_URL = "/profile/"

この方法は第三者が他人のメールアドレスで登録できるようになってしまうので、できるだけ避けるべきです。
どうしても採用する場合は、二要素認証(2FA)などの導入も検討しましょう。

ログアウト時の処理を追加したい

ログアウト時の処理はLogoutViewdispatch()メソッドをオーバーライドします。

次のコードは、ユーザーのログアウト時間を記録したものです。

from allauth.account.views import LogoutView
from django.utils import timezone


class CustomLogoutView(LogoutView):
    def dispatch(self, request, *args, **kwargs):
        if request.user.is_authenticated:
            # ユーザーのプロファイルモデルに最終ログアウト時間を記録
            request.user.profile.last_logout = timezone.now()
            request.user.profile.save()

        return super().dispatch(request, *args, **kwargs)

ユーザーの行動のトラッキングや不正アクセスの検知などを行う目的で実装しました。

なお、上記のコードはOneToOneFieldでユーザーモデルと関連づけられたProfileモデルがあることが前提になります。

他人が投稿したものを表示させない

日記サイトなどで本人が作成した投稿だけを表示させたい場合を解説します。

実装にはUserPassesTestMixinという、ユーザーの判定をするミックスインを使います。

結論となるコードは以下のとおりです。

from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect

class DiaryDetailView(LoginRequiredMixin, UserPassesTestMixin, DetailView):
    model = DiaryEntry
    template_name = "diary/entry_detail.html"
    context_object_name = "entry"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["page_title"] = self.object.title
        return context

    def test_func(self):
        """権限がある人を定義"""
        entry = self.get_object()
        return self.request.user == entry.author

    def handle_no_permission(self):
        """権限がない場合の処理"""
        return redirect("diary:home")

まず、ミックスインの記載順から注意が必要です。

  • ログインしていない人を排除
  • 権限がない人への処理を定義
  • ビューを表示する

といった形で順番が非常に重要になってきますので、コード例のような順序で継承する必要があります。

また、test_func()メソッドには「どんな人に権限があるか」を定義します。

def test_func(self):
    entry = self.get_object()
    return self.request.user == entry.author
karo

self.get_object() は DetailView 固有のメソッドです。

handle_no_permission()メソッドには「権限がない場合の処理」を記載します。

ここでは日記サイトのホーム画面にリダイレクトするようにしました。

def handle_no_permission(self):
    """権限がない場合の処理"""
    return redirect("diary:home")

リダイレクト以外にも、次のような処理が考えられます。

処理内容コード
403エラーraise PermissionDenied()
JSONレスポンスreturn JsonResponse(
{“error”: “message”},
status=403,
)
カスタムエラーページreturn render(
self.request,
“403.html”,
status=403,
)
handle_no_permission の内容

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Pythonが得意。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)