Python | Django | ログインの実装方法
公開日:2021/7/22
Pythonには,DjangoというWebアプリケーションフレームワークがある.フレームワークのため,Djangoを利用するとWebアプリを通常よりも短時間で開発することが可能になる.
前記事にて,「Viewを利用した複数のアプリケーション作成」を記した.前記事での設定をそのまま引き継いだ上で,本記事では,「ログインの実装方法」を以下にて記す.
◆実施環境
Python 3.8.8
Django 3.2.3
■ログインの実装方法
“viewproject/settings.py"の"AUTH_PASSWORD_VALIDATORS"に追記し,以下のように編集する.
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': { # 追記箇所(7~9行目)
'min_length': 6,
}
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
以下URLにアクセスし,"viewproject/settings.py"にどのハッシュ関数を選ぶかを決める.
“https://docs.djangoproject.com/en/3.2/topics/auth/passwords/#included-hashers"
“viewproject/settings.py"の"AUTH_PASSWORD_VALIDATORS"のすぐ上に以下のように追記する.ハッシュ関数は,上から順に利用され,利用できなくなる可能性があるので,複数入力する.今回は7つの関数を入力した.
PASSWORD_HASHERS = [ # 追記箇所(1~9行目)
'django.contrib.auth.hashers.Argon2PasswordHasher',
'django.contrib.auth.hashers.BCryptSHA256PasswordHasher',
'django.contrib.auth.hashers.BCryptPasswordHasher',
'django.contrib.auth.hashers.PBKDF2PasswordHasher',
'django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher',
'django.contrib.auth.hashers.SHA1PasswordHasher',
'django.contrib.auth.hashers.MD5PasswordHasher',
]
AUTH_PASSWORD_VALIDATORS = [
コマンドプロンプトを起動し,”conda activate 仮想環境名”を実行し,仮想環境に移行する(詳細はこちら参照).その後,"pip install django[argon2]"を実行する.以下が出力されると成功.
(djangoenv) C:\Users\shiro>pip install django[argon2]
Requirement already satisfied: django[argon2] in c:\users\shiro\anaconda3\envs\djangoenv\lib\site-packages (3.2.3) # 以下出力箇所
Requirement already satisfied: pytz in c:\users\shiro\anaconda3\envs\djangoenv\lib\site-packages (from django[argon2]) (2021.1)
Requirement already satisfied: sqlparse>=0.2.2 in c:\users\shiro\anaconda3\envs\djangoenv\lib\site-packages (from django[argon2]) (0.4.1)
Requirement already satisfied: asgiref<4,>=3.3.2 in c:\users\shiro\anaconda3\envs\djangoenv\lib\site-packages (from django[argon2]) (3.3.4)
Collecting argon2-cffi>=19.1.0
Downloading argon2_cffi-20.1.0-cp38-cp38-win_amd64.whl (42 kB)
|████████████████████████████████| 42 kB 340 kB/s
Collecting cffi>=1.0.0
Downloading cffi-1.14.6-cp38-cp38-win_amd64.whl (179 kB)
|████████████████████████████████| 179 kB 6.4 MB/s
Collecting six
Downloading six-1.16.0-py2.py3-none-any.whl (11 kB)
Collecting pycparser
Using cached pycparser-2.20-py2.py3-none-any.whl (112 kB)
Installing collected packages: pycparser, six, cffi, argon2-cffi
Successfully installed argon2-cffi-20.1.0 cffi-1.14.6 pycparser-2.20 six-1.16.0
“user/models.py"に追記し,以下編集をする.
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
website = models.URLField(blank=True)
picture = models.FileField(upload_to='user/', blank=True)
def __str__(self):
return self.user.username
“user"フォルダに"forms.py"を作成する.プロジェクトの構成は以下のようになる.
“user/forms.py"を以下のように編集する.
from django import forms
from django.contrib.auth.models import User
from user.models import Profile
class UserForm(forms.ModelForm):
username = forms.CharField(label='名前')
age = forms.IntegerField(label='年齢')
email = forms.EmailField(label='メールアドレス')
password = forms.CharField(label='パスワード', widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username', 'age', 'email', 'password')
class ProfileForm(forms.ModelForm):
website = forms.URLField(label='ホームページ')
picture = forms.FileField(label='写真')
class Meta():
model = Profile
fields = ('website', 'picture')
“user/views.py"に追記し,以下のように編集する.
from django.shortcuts import render
from user.forms import UserForm, ProfileForm # 追記箇所
def user_list(request):
return render(request, 'user/user_list.html')
def index(request): # 以下追記箇所
return render(request, 'user/index.html')
def register(request):
user_form = UserForm(request.POST or None)
profile_form = ProfileForm(request.POST or None, request.FILES or None)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return render(request, 'user/registration.html', context={
'user_form':user_form,
'profile_form':profile_form,
})
“user/urls.py"に追記し,以下のように編集する.
from django.urls import path
from . import views
app_name = 'user'
urlpatterns = [
path('user_list/', views.user_list, name='user_list'),
path('index/', views.index, name='index'), # 追記箇所(8~9行目)
path('register/', views.register, name='register'),
]
“user/forms.py"にて写真をアップロードするので,"viewproject/settings.py"に以下コードを追記する.
STTICFILES_DIRS = [
STATIC_DIR,
]
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # 以下追記箇所
MEDIA_URL = '/media/'
“viewproject"に"media"フォルダを作成する.プロジェクトの構成は以下になる.
“viewproject/templates/user"に以下のように"BASE.html","index.html","registration.html"を作成する.
“BASE.html"を以下のように編集する.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<nav>
<a href="{% url 'user:index' %}">ホーム</a>
<a href="{% url 'admin:index' %}">管理画面</a>
<a href="{% url 'user:register' %}">登録画面</a>
</nav>
<div>
{% block content %}
{% endblock %}
</div>
</body>
</html>
“index.html"には以下のように編集する.
{% extends "user/base.html" %}
{% block content %}
<h2>ログインページ</h2>
{% endblock %}
“registration.html"は以下のように編集する.
{% extends "user/base.html" %}
{% block content %}
<h2>登録画面</h2>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
{{ user_form.as_p }}
{{ profile_form.as_p }}
<input type="submit" value="登録">
</form>
{% endblock %}
“viewproject/settings.py"の以下箇所を編集する.
DEBUG = True # 変更箇所
ALLOWED_HOSTS = ['127.0.0.1']
ターミナルを開き,”conda activate 仮想環境名”を実行し,仮想環境に移行する(移行方法の詳細はこちら).その後,"cd viewproject"を実行することによって,”viewproject”のディレクトリに移動し,”python manage.py makemigrations アプリ名”を実行する.アプリ名は,"user"とした.以下が出力される.
(djangoenv) C:\Users\shiro\Desktop\210517_python development\myviewtest\viewproject
>python manage.py makemigrations user
Migrations for 'user': # 以下出力箇所
user\migrations\0001_initial.py
- Create model Profile
その後,"python manage.py migrate user"を実行する.以下が出力される.
(djangoenv) C:\Users\shiro\Desktop\210517_python development\myviewtest\viewproject
>python manage.py migrate user
Operations to perform: # 以下出力箇所
Apply all migrations: user
Running migrations:
Applying user.0001_initial... OK
SQLiteをインストールし(詳細はこちら参照),"SQLITE EXPLORER"を開くと,"user_profile"を以下赤枠にて確認できる.
ブラウザで画面を立ち上げるため,ターミナルにて,"python manage.py runserver"を実行する.
(djangoenv) C:\Users\shiro\Desktop\210517_python
development\myviewtest\viewproject>python manage.py runserver
System check identified no issues (0 silenced). # 以下出力箇所
July 21, 2021 - 16:31:59
Django version 3.2.3, using settings 'viewproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
上記の"http://127.0.0.1:8000/"をクリックすると,ブラウザにて以下画面が表示される.
“http://127.0.0.1:8000/user/index"を入力すると以下ページに遷移する.
上記ページの"管理画面"をクリックすると以下ページに遷移する.
上記ページの"登録画面"をクリックすると以下ページに遷移する.
以下のように記述し,"登録"をクリックする.
ターミナルには以下のように出力される.
[21/Jul/2021 17:00:47]
"POST /user/register/ HTTP/1.1" 200 1243
“SQLITE EXPLORER"の"auth_user"を右クリックし,"Show Table"をクリックすると以下が確認できる.
上記"管理画面"にログインするには,"auth_user"の"is_staff"が1である必要がある."is_staff=1″を作成するには,ターミナルにて,”conda activate 仮想環境名”を実行し,仮想環境に移行する.その後,"viewproject"のディレクトリにて,"python manage.py createsuperuser"を実行する.以下のように出力されるので,Usernameなどを入力する.今回,"highest"という名のuserを登録した."Superuser created successfully."が出力されると登録成功となる.
(djangoenv) C:\Users\shiro\Desktop\210517_python development\myviewtest\viewproject
>python manage.py createsuperuser
Username: highest # 以下出力箇所
Email address: highest@gmail.com
Password:
Password (again):
Superuser created successfully.
“SQLITE EXPLORER"の"auth_user"を右クリックし,"Show Table"をクリックすると,追加した内容が以下にて確認できる.
この情報を用いて,上記ページの"管理画面"にログインすると以下のように管理画面の中に遷移する.
上記の"Users"をクリックすると,以下画面に遷移する.先ほど登録した"highest"も確認できる.
“Profile"の内容を管理画面で表示するには,"viewproject/user/admin.py"を以下のように編集する.
from django.contrib import admin
from user.models import Profile
admin.site.register(Profile)
上記を保存し,"管理画面"にログインすると以下のように"Profile"が追加された.
“user/forms.py"に追記し,以下のように編集する.
from django import forms
from django.contrib.auth.models import User
from user.models import Profile
class UserForm(forms.ModelForm):
username = forms.CharField(label='名前')
age = forms.IntegerField(label='年齢')
email = forms.EmailField(label='メールアドレス')
password = forms.CharField(label='パスワード', widget=forms.PasswordInput())
class Meta():
model = User
fields = ('username', 'age', 'email', 'password')
class ProfileForm(forms.ModelForm):
website = forms.URLField(label='ホームページ')
picture = forms.FileField(label='写真')
class Meta():
model = Profile
fields = ('website', 'picture')
class LoginForm(forms.Form): # 以下追記箇所
username = forms.CharField(label='名前', max_length=50)
password = forms.CharField(label='パスワード', widget=forms.PasswordInput())
confirm_password = forms.CharField(label='パスワード再入力', widget=forms.PasswordInput())
def clean(self):
cleaned_data =super().clean()
password = cleaned_data['password']
confirm_password = cleaned_data['confirm_password']
if password != confirm_password:
raise forms.ValidationError('パスワードが一致しません')
“user/views.py"に追記し,以下のように編集する.
from django.shortcuts import render, redirect # 以下修正箇所(1~5行目)
from django.http import HttpResponse
from user.forms import UserForm, ProfileForm, LoginForm
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
def user_list(request):
return render(request, 'user/user_list.html')
def index(request):
return render(request, 'user/index.html')
def register(request):
user_form = UserForm(request.POST or None)
profile_form = ProfileForm(request.POST or None, request.FILES or None)
if user_form.is_valid() and profile_form.is_valid():
user = user_form.save()
user.set_password(user.password)
user.save()
profile = profile_form.save(commit=False)
profile.user = user
profile.save()
return render(request, 'user/registration.html', context={
'user_form':user_form,
'profile_form':profile_form,
})
def user_login(request): # 以下追記箇所
login_form = LoginForm(request.POST or None)
if login_form.is_valid():
username = login_form.cleaned_data.get('username')
password = login_form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user:
if user.is_active:
login(request, user)
return redirect('user:index')
else:
return HttpResponse('アカウントがアクティブでない')
else:
return HttpResponse('ユーザーが存在しません')
return render(request, 'user/login.html', context={
'login_form': login_form
})
@login_required
def user_logout(request):
logout(request)
return redirect('user:index')
@login_required
def status(request):
return HttpResponse('ログインしています')
“user/urls.py"に追記し,以下のように編集する.
from django.urls import path
from . import views
app_name = 'user'
urlpatterns = [
path('user_list/', views.user_list, name='user_list'),
path('index/', views.index, name='index'),
path('register/', views.register, name='register'),
path('user_login/', views.user_login, name='user_login'), # 追記箇所(10~12行目)
path('user_logout/', views.user_logout, name='user_logout'),
path('info/', views.info, name='info'),
]
“viewproject/templates/user"に"login.html"を以下のように作成する.
“login.html"を以下のように編集する.
{% extends "user/base.html" %}
{% block content %}
<h2>ログイン画面</h2>
<form method="POST">
{% csrf_token %}
{{ login_form.as_p }}
<input type="submit" value="ログイン">
</form>
{% endblock %}
“viewproject/templates/user/BASE.html"に追記し,以下のように編集する.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<nav>
<a href="{% url 'user:index' %}">ホーム</a>
<a href="{% url 'admin:index' %}">管理画面</a>
{% if user.is_authenticated %}
<a href="{% url 'user:user_logout' %}">ログアウト</a>
{% else %}
<a href="{% url 'user:register' %}">登録画面</a>
<a href="{% url 'user:user_login' %}">ログイン</a>
{% endif %}
<a href="{% url 'user:status' %}">status</a>
</nav>
<div>
{% block content %}
{% endblock %}
</div>
</body>
</html>
ターミナルを開き,"python manage.py runserver"を実行する.
(djangoenv) C:\Users\shiro\Desktop\210517_python development\myviewtest\viewproject
>python manage.py runserver
System check identified no issues (0 silenced).
July 22, 2021 - 01:26:50
Django version 3.2.3, using settings 'viewproject.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
上記の"http://127.0.0.1:8000/"をクリックするとブラウザにて以下画面が開く
上記の"http://127.0.0.1:8000/user/index"を入力すると,以下画面に遷移する.
上記の"ログイン"をクリックすると以下画面に遷移する.
上記で作成した名前とパスワードを入力し,"ログイン"をクリックすると以下ログインページに遷移する.
“status"をクリックすると,以下ページが表示される.
■参照
https://docs.djangoproject.com/en/3.2/topics/auth/passwords/#included-hashers
https://docs.djangoproject.com/en/3.2/topics/auth/passwords/#-django.contrib.auth.password_validation
以上