DjangoでWebサイトを作る際に、accountsアプリケーションを作成することなくログイン認証をする必要に迫られたのですが、包括的、体系的に説明しているサイトに出会えなかったため書き残します。
環境
- Python 3.7.0
- Django 2.1.4
(2020/3月追記: Python 3.7.4, Django 3.0でも動作確認済みです)
ディレクトリ構成
ディレクトリは以下のように構成されています。ここでは、ログイン認証に必要な最低限のものを書きます。
mysite/
├ manage.py
├ mysite/
│ ├ settings.py
│ └ urls.py
└ myapp/
├ urls.py
├ views.py
├ forms.py
├ models.py
└ templates/
├ base.html
└ myapp/
├ mymodel_detail.html
├ signup.html
└ などいろいろなhtml
よくあるログイン認証の紹介では、accountsアプリケーションを使うために、
$ python manage.py startapp accounts
を用いて、mysite/accounts/
を作成、mysite/mysite/settings.py
のINSTALLED_APPSに'accounts.apps.AccountsConfig'
を追加する、とあると思いますが、今回はINSTALLED_APPSにaccountsアプリケーションを追加せずにログイン認証をします。
なお、今回の場合でもログイン認証だけを考えるならば、mysite/mysite/models.py
の変更は不要です。
前提となる設定
まず、mysite/mysite/settings.py
にmyappをアプリケーションとして追加しています。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp' # Here
]
また、ルートのURLとして、myapp
を登録しています。
ROOT_URLCONF = 'myapp.urls'
さらに、ログインしなければログイン関係やサインアップ関係のページ以外は一切見れないようにします(設定方法は後述)。
必要な設定
最初に必要な設定をまとめると、次のようになります。
-
mysite/mysite/settings.py
にログインやログアウトのためのURLとそれぞれのリダイレクト先を明記 -
mysite/myapp/urls.py
にログイン、ログアウトなどのURLを登録 -
mysite/myapp/views.py
に必要ならばログイン、ログアウトなどを登録、さらにログイン時以外に見れないようにする -
mysite/myapp/templates/
にログインなどのhtmlを作成
mysite/mysite/settings.py
の設定
以下では、名前付きURLパターンを使います。これにより、アプリケーションごとに名前空間の分離を図ることができます。myapp
をアプリケーションとしてsettings.py
で登録していることに注意してください。
名前付きURLパターンの公式のマニュアル
https://docs.djangoproject.com/ja/2.1/topics/http/urls/#naming-url-patterns
django.contrib.auth、つまりログインなどに関するURLの公式のマニュアル
https://docs.djangoproject.com/ja/2.1/ref/settings/#auth
ログイン、ログアウトのURLの設定
ログイン、ログアウトのURLに用いるURLは、通常はaccountsアプリケーションの存在を仮定しています。この設定のデフォルトでは、
LOGIN_URL='accounts/login/' # ログイン
LOGOUT_URL='accounts/logout/' # ログアウト
とされているため、今回は、
LOGIN_URL='myapp:login' # ログイン
LOGOUT_URL='myapp:logout' # ログアウト
と設定します。myapp:login
などとしているのは名前付きURLパターンを用いているためです。ここで、 login
や logout
は myapp.views
のなかで、ログイン、ログアウトのURLを name='login'
などと名前の登録をすることで使えるようになり、この機能と同じ myapp.views
内の app_name='myapp'
の登録により、URLを変更したとしても名前で追うことができ、ハードコーディングをしないでいいようになります。(これらの登録も後の項目で載せます)
リダイレクト先の設定
ログイン、ログアウトが完了した後に遷移するURL(リダイレクト先)を登録する必要もあります。デフォルト値も併せて紹介すると、
LOGIN_REDIRECT_URL='/accounts/profile/' # ログイン
LOGOUT_REDIRECT_URL='None' # ログアウト
です。例えば、ログインした後に遷移するURLをmyapp/home
、ログアウトした後に遷移するURLをmyapp/login
にする(ログインページにする)ならば、以下のように設定します。
LOGIN_REDIRECT_URL='myapp:home' # ログイン
LOGOUT_REDIRECT_URL='myapp:login' # ログアウト
このようにリダイレクト先を設定しておけば、ログインやログアウトが完了すると自動的に画面が遷移します。
mysite/myapp/templates/
の存在を明記すべきかどうか
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
で
'DIRS': [os.path.join(BASE_DIR, 'templates')],
とすべきと書いてあるページもありますが、今回はなくても大丈夫です。(もしもだめだったら追加してください)
mysite/myapp/urls.py
にログイン、ログアウトなどを登録
作成したものは以下のものです。
from django.urls import path, include
from . import views # mysite/myapp/views.pyをインポート
from django.contrib.auth import views as auth_views
app_name = 'myapp'
urlpatterns = [
path('home/', views.home, name='home'),
path('login/', auth_views.LoginView.as_view(template_name='myapp/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('signup/', views.signup, name='signup'),
path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
# path('password_reset/', auth_views.PasswordResetView.as_view(template_name='myapp/password_reset.html'), name='password_reset'),
# path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
# path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
# path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]
ここでは、パスワード変更などのページについてはすべてコメントアウトしていますが、これらを用いれば他の機能も拡張できます。また、アプリケーションとしてmyapp
を用いるため、app_name = 'myapp'
と書いていることに注意してください。
また、サインアップに関するビューはデフォルトでないですが、それ以外はdjango.contrib.auth
を使うことができます。
accountsアプリケーションを用いる場合には一括でaccounts/
下に一括で利用することができるようになっていますが、accountsアプリケーションを利用せずとも、個別に上に載せたものは上記のように利用することができます。
ログインなどに関するビューもデフォルトのままでよいなら自分でmysite/myapp/views.py
に登録する必要もありません(個別にカスタマイズしたいならこれらのクラスを継承したものを作成する必要があります)。
ここで、ログインのみ引数を与えましたが、これはテンプレートの存在場所を指定するためです。ログインやログアウトのhtmlは、デフォルトでは以下の通りです。
- ログイン画面: templates/registration/login.html
- ログアウト画面: templates/registration/logged_out.html
これは、上記のコードのようにas_view
の引数にtemplate_name=(mysite/myapp/templates/以下の場所の指定)
と指定することで変更することができます。
mysite/myapp/views.py
関数の作成
ログインやログアウトなど、django.contrib.auth
のままでよいならば書く必要はありませんが、メールアドレス認証など、独自のクラスが必要ならば作成する必要がありますが、いらないならば特になにもしなくてよいです。
しかし、サインアップに関するビューはないため、自分で作る必要があります。
例えば、次のようにして作成できます。
from django.contrib.auth.forms import UserCreationForm # ユーザー作成のため追加
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
return redirect('myapp/main')
else:
form = UserCreationForm()
return render(request, 'myapp/signup.html', {'form': form})
ログインしていないときに見れないようにする
ログインしていないときにページを見れないようにするためには、mysite/myapp/views.py
の途中で、
from django.contrib.auth.decorators import login_required
# ログインしていないときにも見れるページに関する関数
# 例えば、def signup(request)など
@login_required
# ログインしているときのみ見れるページに関する関数
# 例えば、def main(request)など
を書くとよいです。クラスを用いているときには、
from django.contrib.auth.mixins import LoginRequiredMixin
# ログインしているときのみ見れるページのクラスベースのビュー
def myclass(LoginRequiredMixin, ...):
...
のように、最初にLoginRequiredMixin
を継承します。
mysite/myapp/templates/
にログインなどのhtmlを作成
ログインのためのhtmlを作成します。
詳細は省略しますが、
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
のように、django.contrib.auth
のLoginView
を用いているならば、{{ form.username }}
と{{ form.password }}
でユーザー名とパスワードを利用でき、
<input type="submit" id="login_button" class="login_button" name="login_button" value="ログイン" onclick="location.href='./../home'" />
<input name="next" type="hidden" value="{{ next }}"/>
などとすれば、ログインボタンが作成できます。
これで、ログインができるようになりました。
なお、logout用のhtmlファイルはログアウト後のページを作らないならば(今回の場合はログイン画面に遷移させているので)不要です。
まとめ
みなさん快適なDjangoライフを!