(準備中)【Django】簡単なログインフォーム実装を通して、関数ベースビューのログイン機能を学ぶ
はじめに
私はログインに取っつきづらさを感じていたのだが、意外と簡単だということに気づいた。そこで勉強のため、下記のサイトを参考にアプリをつくることにした。
【Django】ログイン機能の実現方法(関数ベースビュー編)
こちらでログイン機能について詳しく説明しているので、はっきり言って私の記事は必要ない。しかし読んだだけでは身につかないということで、練習のために記事を書いた。
つくるもの
- ログインとログアウトくらいしかできないアプリをつくる。
- ログインへの理解に集中したいので、CSSなどは使わない。
ユーザー登録画面
ユーザー名とメールアドレス、パスワード、パスワード(確認用)を入力して、ユーザー登録を行う。
(TODO: 画面の画像)
ログイン画面
登録した情報を入力してログインする。
(TODO: 画面の画像)
メイン画面
アプリの本体。Hello Login!
という素晴らしい文字が表示される。
(TODO: 画面の画像)
ログアウト画面
ログアウトしたことを知らせる。
(TODO: 画面の画像)
初期設定
Django用のディレクトリ作成
- 任意の場所にDjango用のディレクトリをつくる。ここでは
django
という名前にした。 - VSCodeを開く>
File
>Open Folder
>django
を選択してディレクトリを開く。
仮想環境作成(任意)
仮想環境をつくる。(仮想環境名)には任意の名前を入力する。ここではvenv
。
> python -m venv (仮想環境名)
仮想環境を有効化する。有効化されるとコマンドラインの先頭に環境名が表示される
> venv/Scripts/activate
(venv)>
Djangoインストール
(venv)> pip install django
プロジェクト作成
Django プロジェクトを作成する。(プロジェクト名)には任意の名前を入力する。ここではconfig
。
(venv)> django-admin startproject (プロジェクト名) .
アプリケーション作成
アプリケーションを作成する。(アプリ名)には任意の名前を入力する。ここではlogin_app
。
(venv)> python manage.py startapp (アプリ名)
設定ファイル編集
django/config/settings.py
を編集する。
先ほど作成したアプリケーションを登録する。
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
+ "login_app",
]
言語設定を変更する。
- LANGUAGE_CODE = "en-us"
+ LANGUAGE_CODE = "ja"
タイムゾーンを変更する。
- TIME_ZONE = "UTC"
+ TIME_ZONE = "Asia/Tokyo"
動作確認
(venv)> python manage.py runserver 8000
http://127.0.0.1:8000/
にアクセスすると、いつものロケットが表示される。
(TODO: ロケットの画面)
メイン画面
ログイン・ログアウトの前に、メイン画面をつくる。
View作成
views.py
ファイルを以下のように編集する。render()
でテンプレートを表示するだけである。
from django.shortcuts import render
def index(request):
return render(request, "login_app/index.html")
URL設定
config
ディレクトリ内のurls.py
ファイルを以下のように編集する。
from django.contrib import admin
- from django.urls import path
+ from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
+ path("login_app/", include("login_app.urls")),
]
login_app
ディレクトリにurls.py
ファイルを新規作成し、以下を入力する。
from django.urls import path
from . import views
urlpatterns = [
path("", views.index),
]
Template作成
login_app
ディレクトリに以下のような階層でディレクトリとファイルをつくる。
django
└── login_app
├── views.pyとか
+ └── templates
+ └── login_app
+ └── index.html
index.html
ファイルに以下を入力する。Hello Login!
を表示するだけである。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>メイン画面</title>
</head>
<body>
<h1>Hello Login!</h1>
</body>
</html>
動作確認
http://127.0.0.1:8000/login_app/
にアクセスすると、Hello Login!
が表示される。
(TODO: メイン画面)
ユーザー登録
Modelの作成(省略)
ユーザー登録には名前やパスワードなどのユーザー情報を保存するテーブルが必要である。いつもならテーブルを生成するためにModelをつくるが、ここではDjango標準のUser Model
を使用する。公式はUser
の使用を推奨していないようだが、個人の勉強ということで...
マイグレーション
(venv)> python manage.py migrate
Form作成
login_app
ディレクトリにforms.py
ファイルを新規作成し、以下を入力する。UserCreationForm
が肝である。
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignupForm(UserCreationForm):
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]
View作成
views.py
ファイルに以下を追加する。
- POSTメソッドのときは
is_valid()
でデータの妥当性を検証してからsave()
で保存する。 - GETメソッド(POSTメソッド以外)のときは入力フォームを表示する。
from django.shortcuts import render
from .forms import SignupForm
⋮
def signup_view(request):
if request.method == "POST":
form = SignupForm(request.POST)
if form.is_valid():
form.save()
else:
form = SignupForm()
param = {"form": form}
return render(request, "login_app/signup.html", param)
URL設定
urls.py
ファイルに以下を追加する。
urlpatterns = [
⋮
path("signup/", views.signup_view, name="signup"),
]
Template作成
templates/login_app
ディレクトリにsignup.html
ファイルをつくり、以下を入力する。
-
{{ form.as_p }}
に入力フォームが表示される。 -
{{ form }}
だけでも入力フォームを表示できるが、.as_p
をつけることで各入力項目を<p>
タグで囲むことができる。必須ではないが、こちらの方が見やすい。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>ユーザー登録</title>
</head>
<body>
<h1>ユーザー登録</h1>
<form action="{% url 'signup' %}" method="post">
{% csrf_token %} {{ form.as_p }}
<input type="submit" value="登録" />
</form>
</body>
</html>
動作確認
http://127.0.0.1:8000/login_app/signup/
にアクセスすると、ユーザー登録画面が表示される。各項目に入力し登録ボタンを押すと、ユーザー登録が行われる。
(TODO: ユーザー登録画面の画像)
テーブルの中身を確認
今回の実装では、登録しても画面が変わらない。このままでは登録できているか確認しづらいので、VSCodeの拡張機能SQLite Viewer
でチェックする。
- 拡張機能
SQLite Viewer
をインストールする。 -
db.sqlite3
ファイルを開く。 -
auth_user
に先ほど登録した情報が表示される。すげえ!
(TODO: db.sqlite3の画像)
ログイン
Form作成
forms.py
に以下を追加する。AuthenticationForm
が肝である。これを継承すればログインフォームを表示できる。
from django.contrib.auth.forms import UserCreationForm, AuthenticationForm # 追加
from django.contrib.auth.models import User
⋮
class LoginForm(AuthenticationForm):
pass
View作成
views.py
ファイルに以下を追加する。
- POSTメソッドのときは認証を行う。認証OKのときだけ
login
関数を実行する。 - GETメソッド(POSTメソッド以外)のときはログインページを表示する。
from django.contrib.auth import login
from django.shortcuts import render
from .forms import LoginForm, SignupForm
⋮
def login_view(request):
if request.method == "POST":
form = LoginForm(request, data=request.POST)
if form.is_valid():
user = form.get_user()
if user:
login(request, user)
return redirect(to="/login_app/")
else:
form = LoginForm()
param = {"form": form}
return render(request, "login_app/login.html", param)
URL設定
urls.py
ファイルに以下を追加する。
urlpatterns = [
⋮
path("login/", views.login_view, name="login"),
]
Template作成
templates/login_app
ディレクトリにlogin.html
ファイルをつくり、以下を入力する。
-
{{ form.as_p }}
にログインフォームが表示される。
<!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 }}
<input type="submit" value="ログイン" />
</form>
</body>
</html>
動作確認
-
http://127.0.0.1:8000/login_app/login/
にアクセスすると、ログイン画面が表示される。 - 先ほど登録したユーザー情報を入力してログインボタンを押すと、メイン画面に遷移する。
-
auth_user
テーブルのlast_login
を確認すると値が入っているはず。last_login
は最終ログインの日時である。 -
session_key
テーブルを確認すると、値が入っている。
ログアウト
View作成
views.py
ファイルに以下を追加する。logout()
を実行してrender()
でテンプレートを表示するだけである。
from django.contrib.auth import login, logout
from django.shortcuts import render
from .forms import LoginForm, SignupForm
⋮
def logout_view(request):
logout(request)
return render(request, "login_app/logout.html")
URL設定
urls.py
ファイルに以下を追加する。
urlpatterns = [
⋮
path("logout/", views.logout_view, name="logout"),
]
Template作成
templates/login_app
ディレクトリにlogout.html
ファイルをつくり、以下を入力する。ログアウトしたことを示すだけである。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>ログアウト</title>
</head>
<body>
<p>ログアウトしました</p>
</body>
</html>
動作確認
-
http://127.0.0.1:8000/login_app/logout/
にアクセスすると、ログアウト画面が表示される。 -
django_session
テーブルを確認すると、レコードが消えているはずである。
未ログインユーザーからのアクセス禁止
ログイン・ログアウトを実装したが、それらとメイン画面の紐づけをまだ行っていない。したがってログインしていない状態でも、今のところメイン画面のHello Login!
を表示することができる。ログインが必要なページに未ログインユーザーがアクセスした場合、他のページへリダイレクトするよう編集する。
View編集
views.py
ファイルに以下を追加する。関数に@login_required
をつけるだけ。
+ from django.contrib.auth.decorators import login_required
from django.shortcuts import render
+ @login_required
def index(request):
return render(request, "login_app/index.html")
リダイレクト先を設定
settings.py
に以下を追加する。LOGIN_URL
にリダイレクト先のページを指定する。
⋮
+ LOGIN_URL = '/login_app/login/'
動作確認
- まず
http://127.0.0.1:8000/login_app/logout
でログアウトする。 - それから
http://127.0.0.1:8000/login_app/
にアクセスすると、メイン画面ではなくログイン画面にリダイレクトするはずである。
ユーザーに応じたページ処理
ログインの目的には「未ログインユーザーのアクセスを禁止する」以外にも、「ユーザーに応じて表示を変える」というものもある。そこでログインユーザーの情報(ユーザーネームとメールアドレス)をメイン画面に表示させるよう編集する。
View編集
views.py
ファイルを以下のように編集する。
-
request
のuser
属性にユーザー情報が入っているので取得する。 - その値をコンテキストに格納し、
render()
でテンプレートに表示する。
@login_required
def index(request):
- return render(request, "login_app/index.html")
+ user = request.user
+ params = {"user": user}
+ return render(request, "login_app/index.html", params)
Template編集
index.html
ファイルを以下のように編集する。{{ user.xxxx }}
でViewから渡されたユーザー情報を表示させる。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>メイン画面</title>
</head>
<body>
<h1>Hello Login!</h1>
+ <ul>
+ <li>username: {{ user.username }}</li>
+ <li>email: {{ user.email }}</li>
+ </ul>
</body>
</html>
動作確認
http://127.0.0.1:8000/login_app/login
でログインすると、メイン画面にusername
とemail
が表示される。
(TODO: メイン画面)
GitHub
TODO: コード載せる
感想
@login_required
と書くだけで未ログインユーザーのアクセスを禁止できたり、AuthenticationForm
を継承するだけでログインフォームをお手軽に実装できたりと、「え!それだけで!?」と思った。
次はクラスベースビューのログインについて調べたい。