Django:ログイン後に別アプリ(CMSコンパネ)に飛ばそうとして悩んだ件
Django:ログイン後に別アプリ(CMSコンパネ)に飛ばそうとして悩んだ件
現在作成しているサイトがほぼ出来上がったので、次は操作部。
「サイトをDjangoで書いてるんだからCMSにしないとね」と言う事で、ログイン後のCMSコンパネの作成なのですが、ここでチョット躓きました。
今現状も最良の解決なのかわからないのですが、ユーザーによる篩分けもできるので取り合えず形になったかなと。
『やりたいこと』について
やりたいことは下の通りです。
- ログイン後、サイト構築用画面(CMSコンパネ)にJUMP
- ユーザーのランク(ロール)によって表示する内容を変更(ふるい分け)
そのための構成として採用したのが【accountsアプリ】です。
accountsアプリの導入について
作業はたった2つです。
- SSHでログインしてコマンド実行 [ python manage.py startapp accounts ]
- settings.pyにaccountsアプリを追加
1 |
python manage.py startapp accounts |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.sites', 'allauth', 'allauth.account', 'allauth.socialaccount', # ▼追加▼ 'accounts.apps.AccountsConfig', ] |
これはサイト構築の最初の工程で準備しておかないと痛い目見るそうです。
私の環境では既に実行&実装済み。なので、ログインはできるのですがログイン後のコンパネがない状態です。
まぁね、adminで『Django 管理サイト』からテーブル弄れるんでコンパネ造作不要ですから。
でも、納品となると「『Django 管理サイト』で弄ってください」って訳にもいかないのでコンパネが必要です。
今回ハマったポイント
ホームページ側アプリと別にコンパネ用アプリを用意しました。
そして、settings.pyに次のように記載しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
AUTH_USER_MODEL = 'accounts.CustomUser' #django-allauthで利用するdjango.contrib.sitesを使う為に差異と識別用IDを設定 SITE_ID = 1 #メールアドレス認証に変更する設定 ACCOUNT_AUTHENTICATION_METHOD = 'email' ACCOUNT_USERNAME_REQUIRED = False #サインアップにメールアドレスを挟む(送信する)よう設定(none=送信しない, mandatory=送信する) ACCOUNT_EMAIL_VERIFICATION = 'none' ACCOUNT_EMAIL_REQUIRED = True #ログイン・ログアウト後の遷移先を設定 LOGIN_REDIRECT_URL = 'cop:index' ACCOUNT_LOGOUT_REDIRECT_URL = 'web:index' #ログアウトリンクのクリック一発でログアウトする設定 ACCOUNT_LOGOUT_ON_GET = True |
15行目はリダイレクト先URLの登録。ここにコンパネアプリ(cop)のindexへJUMPするよう登録しました。
16行目はログアウトした時の画面遷移先です。
で、ログイン処理を実行するとこんなエラーがでてログインの処理もしてくれなくなりました。
色々調べてみると、この現象はPOSTの先がアプリを超えるときに発生するらしい。
解決に向けた情報が載っているサイト
まずは解決できる情報先のサイトリンクを記載します。
Django公式 / 参考サイト
せっかくなのでやってみた実験とその結果
エラーを超える方法はわかったので「ちょうど良い機会」と思い実験してみました。
- LOGIN_REDIRECT_URL = ‘cop:index’ として URL:/accounts/login からログイン
- LOGIN_REDIRECT_URL = ‘cop:index’ として URL:/accounts/login/?next=/cop/ からログイン
- LOGIN_REDIRECT_URL = ‘/cop/’ として URL:/accounts/login からログイン
- LOGIN_REDIRECT_URL = ‘/accounts/login/’ として URL:/accounts/login からログイン
- LOGIN_REDIRECT_URL = ” として URL:/accounts/login からログイン
結果
- ログイン&画面遷移成功【実験2 / 5】
- ログイン成功&画面遷移失敗【実験4】
- ログイン失敗&画面遷移失敗【実験1 / 3】
実験結果からわかる通り、ログイン処理ページを提供しているアプリと別のアプリへ画面遷移する場合は1つの例外を除いてエラーが発生しました。
1つの例外とは、GETでログイン後の遷移先を指定する方法です。※上の【実験2】になります。
つまりは、この過程で発生しているエラーは『ログイン後の画面遷移先不明』で発生しているわけです。
原因は分かった、対応策は?
『遷移先不明』で発生しているなら「遷移先を明確にすればよい」となります。
ググって出てくる対応策をまとめると4通りほどあることがわかります。
- ログイン後のコンパネを別アプリで立ち上げない ※同一アプリ内で作成する
- app\urls.pyに遷移先URLを明示しておく ※別アプリ内のmodels.pyをimportしておく必要がある
- ログインURLに必ず [ ?next= ] を付けて運用する ※運用でのカバー、getのない場合は変わらずエラー発生
- 同一アプリ内にログイン後の遷移先を用意、そこからredirectにて別アプリのコンパネに誘導する
今回は【項目4】の方法を採用することにしました。
ログイン後の遷移先で別アプリのコンパネに誘導する
- settings.py の LOGIN_REDIRECT_URL に app:sieving を登録 ※app=ドメイン直下のindexを管理するアプリ
- app\views.py に def SievingView(request) を作成 ※最初の篩分けを記載(ここがapp:sieving)
- views.SievingViewをapp\urls.pyに登録
- 2で記載したリダイレクト先(cop\index)を作成し groups_id(role)で遷移ページを変える※2段階目の篩分け
作業としては上の通りです。
ポイントは2項目の別アプリのredirectを記載する際に【HttpResponseRedirect】を呼び出すこと。
ノーマルなredirectを呼び出すとエラーが発生します。
実際に書いたスクリプト
■setting.py
1 2 3 4 |
(前略) #ログイン・ログアウト後の遷移先を設定 LOGIN_REDIRECT_URL = 'app:sieving' ACCOUNT_LOGOUT_REDIRECT_URL = 'app:index' |
■app\views.py
1 2 3 4 5 6 7 8 9 10 11 12 |
(前略) from django.shortcuts import render,redirect from django.http import HttpResponseRedirect (中略) @login_required def SievingView(request): if request.user.is_authenticated: """ログインユーザーに対する処理""" return HttpResponseRedirect('/cop')#コンパネに遷移 else: """匿名ユーザーに対する処理""" return redirect('/accounts/logout')#強制ログアウト |
■app\urls.py
1 2 3 4 5 6 7 |
from django.urls import path from . import views (中略) urlpatterns = [ (中略) path('sieving', views.SievingView, name="sieving"),#追加 ] |
■cop\views.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import logging import datetime from django.shortcuts import render from django.contrib.auth.decorators import login_required from web.models import Contents logger = logging.getLogger(__name__) @login_required def CopIndexView(request): if request.user.is_authenticated: """ユーザー名 取得合成""" user = request.user.last_name + " " + request.user.first_name if request.user.groups_id == 1: #開発者Consoleに遷移 return render(request, 'creator/index.html') elif request.user.groups_id== 2: #管理者Consoleに遷移 return render(request, 'manager/index.html') elif request.user.groups_id== 3: #利用者Consoleに遷移 return render(request, 'user/index.html') else: #ROLE設定(groups_id)のない場合は強制ログアウト return HttpResponseRedirect('/accounts/logout') |
チョット解説
Laravelではroleという値を入れていましたが、Djangoのaccountsアプリでは初期値でgroups_idというカラムが用意されています。これは一緒に作成されている【accounts_customuser_groups】テーブルとリレーションが張られています。こいつを使えば、ログイン後の処理の処理分け(処理の可否含め)が出来るようになります。
2020/02/08追記
ごめんなさい、groups_id とそのリレーションは自分で修正していたようです。
django-allauthの初期値に入っているのは【groups】というカラムでした。
だいぶ前に外観だけ構成した際に作っていたようです。誤情報申し訳ございませんでした。
まとめ
今回実装した形が最善であるのか、まだまだ「やりよう」はあると思います。
まぁそれでもアイディアでここまでは作れるぞと。
-
前の記事
WEBデザイン:言語選択で【国旗】を選ぶことの是非について 2021.01.29
-
次の記事
Django:別アプリのmodels.pyに書いたテーブルを使う時のimport方法と注意点 2021.02.05
コメントを残す