はじめに
前回(環境構築編)で使用したプロジェクトを引き継いで作成する。
開発環境
・Windows10 professional 64bit
・Python 3.7.1
・Django 2.1.2
・MySQL 8.0.12
ユーザ認証
ログイン
・ログインをしトップページを表示する機能を作成する。
URL設定
プロジェクトで画面のURLを設定する
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('accounts.urls')),
]
アプリ内でもURLを設定するために,accounts直下にurls.py
を作成
from django.urls import path
from . import views
app_name = 'accounts'
urlpatterns = [
path('', views.Login.as_view(), name='login'),
path('top/', views.Top.as_view(), name='top'),
path('logout/', views.Logout.as_view(), name='logout'),
]
ログインフォームを作成するので,accounts直下にforms.py
を作成
from django.contrib.auth.forms import (
AuthenticationForm
)
"""ログインフォーム"""
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
field.widget.attrs['placeholder'] = field.label
表示先を指定するviews.py
を編集
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.views import (
LoginView, LogoutView
)
from django.views import generic
from django.contrib.auth.decorators import login_required
from .forms import LoginForm
"""ログインページ"""
class Login(LoginView):
template_name = 'login.html'
form_class = LoginForm
""" トップページ """
class Top(LoginRequiredMixin, generic.TemplateView):
template_name = 'top.html'
redirect_field_name = 'redirect_to'
"""ログアウトページ"""
class Logout(LoginRequiredMixin, LogoutView):
template_name = 'logout.html'
LoginRequiredMixin
を継承することによって,ログインをしていない場合にログインページにリダイレクトされる
accounts直下にtemplates
フォルダを作成しtemplateの接続先とログインページの設定をsetting.py
で指定する
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates') # 追記
],
'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',
],
},
},
]
# login setting
LOGIN_ERROR_URL = '/login/'
LOGIN_URL = '/login/'
LOGIN_REDIRECT_URL = '../'
ここまでの設定でプロジェクトから表示するページまでのプログラム上の繋がりが完成した
HTML作成
bootstrapをダウンロード
・見た目を整えるためにbootstrapを使うので,bootstrap4のソースコードをダウンロードする
解凍してその中身をそのままtaskMan/static/bootstrap
直下にコピーする
この際static/bootstrap
フォルダを作成する
taskMan
|---accounts
|---static
| |---bootstrap
|
|---taskMan
|---manage.py
そして,staticフォルダがどこにあるのかをプロジェクトのsetting.py
に記載する
# Static file settings
STATIC_ROOT = os.path.join(BASE_DIR, 'assets')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, "static"),
)
ベースHTMLの作成
毎回linkタグやmetaタグなどのヘッダー情報を書くのは大変なので,雛型となるhtmlをtemplates
に作成する
<!DOCTYPE html>
<html lang='ja'>
<head>
{% load staticfiles %}
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="">
<title>{% block title %}{% endblock %}</title>
<link href="{% static 'bootstrap/dist/css/bootstrap.css' %}" rel="stylesheet">
<link href="{% static 'bootstrap/dist/css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static 'bootstrap/dist/css/bootstrap-grid.css' %}" rel="stylesheet">
<link href="{% static 'bootstrap/dist/css/bootstrap-grid.min.css' %}" rel="stylesheet">
<link href="{% static 'bootstrap/dist/css/bootstrap-reboot.css' %}" rel="stylesheet">
<link href="{% static 'bootstrap/dist/css/bootstrap-reboot.min.css' %}" rel="stylesheet">
<link href="{% static 'bootstrap/docs/4.0/examples/dashboard/dashboard.css' %}" rel="stylesheet">
<script type="text/javascript" src="{% static 'bootstrap/assets/js/vendor/jquery-slim.min.js' %}"></script>
<script src="{% static 'bootstrap/assets/js/vendor/anchor.min.js' %}"></script>
<script src="{% static 'bootstrap/assets/js/vendor/clipboard.min.js' %}"></script>
<script src="{% static 'bootstrap/assets/js/vendor/holder.min.js' %}"></script>
<script src="{% static 'bootstrap/assets/js/vendor/popper.min.js' %}"></script>
<script src="{% static 'bootstrap/dist/js/bootstrap.bundle.js' %}"></script>
<script src="{% static 'bootstrap/dist/js/bootstrap.bundle.min.js' %}"></script>
<script src="{% static 'bootstrap/dist/js/bootstrap.js' %}"></script>
<script src="{% static 'bootstrap/dist/js/bootstrap.min.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/alert.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/button.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/carousel.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/collapse.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/dropdown.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/index.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/modal.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/scrollspy.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/tab.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/tooltip.js' %}"></script>
<script src="{% static 'bootstrap/js/dist/util.js' %}"></script>
</head>
<body>
<nav class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0">
<a class="navbar-brand col-sm-3 col-md-2 mr-0" href="/">TaskMan</a>
<div class="form-control form-control-dark w-100">{% block mainT %}{% endblock %}</div>
<div class="form-control form-control-dark w-100" style="text-align: right;">{% block mainL %}{% endblock %}</div>
<ul class="navbar-nav px-3">
<li class="nav-item text-nowrap">
{% block auth %}{% endblock %}
</li>
</ul>
</nav>
{% block body %}{% endblock %}
</body>
</html>
トップページ,ログインページ,ログアウトページをtemplates
にそれぞれ作成する
{% extends "base.html" %}
{% block title %} TaskMan {% endblock %}
{% block mainT %} トップメニュー {% endblock %}
{% block mainL %}UserID : {{ user.get_username }}{% endblock %}
{% block auth %}<a class="nav-link" href="../logout/">ログアウト</a>{% endblock %}
{% block body %}
<h2 style="text-align: center;">Hello World!</h2>
{% endblock %}
{% extends "base.html" %}
{% block title %} TaskMan ログイン {% endblock %}
{% block mainT %} ログイン {% endblock %}
{% block mainL %}UserID : {{ user.get_username }}{% endblock %}
{% block auth %}{% endblock %}
{% block body %}
<div style='padding-top: 50px;'>
<form action="" method="POST">
<div class="col-md-6 offset-md-3">
<div class="card">
<div class="card-body">
{{ form.non_field_errors }}
{% for field in form %}
{{ field }}
{{ field.errors }}
<hr>
{% endfor %}
<button type="submit" class="btn btn-lg btn-primary btn-block" >ログイン</button>
<input type="hidden" name="next" value="{{ next }}" />
{% csrf_token %}
</div>
</div>
</div>
</form>
</div>
{% endblock %}
{% extends "base.html" %}
{% block title %} TaskMan ログアウト {% endblock %}
{% block mainT %} ログアウト {% endblock %}
{% block mainL %}UserID : {{ user.get_username }}{% endblock %}
{% block auth %}{% endblock %}
{% block body %}
<div style="text-align: center; padding-top: 50px;">
<h2 >お疲れ様でした</h2>
<a class="nav-link" href="../login/">ログイン</a>
</div>
{% endblock %}
HTMLも完成したので,localhostにアクセスするとログイン画面が表示される
前回作成したアカウントでログインすると
トップページが表示される
ログアウトをして,トップページに移ろうとするとログインページにリダイレクトする
アカウント登録
URL設定
アカウント登録するためのURLをaccounts/urls.py
に追加
urlpatterns = [
path('', views.Top.as_view(), name='top'),
path('login/', views.Login.as_view(), name='login'),
path('logout/', views.Logout.as_view(), name='logout'),
path('registration/', views.Registration.as_view(), name='registration'), # 追加
path('registration/complete', views.RegistrationComp.as_view(), name='registration_complete'), # 追加
]
アカウント登録用のフォームを作成するので,accounts/forms.py
に以下を追加
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
User = get_user_model()
"""アカウント登録フォーム"""
class RegistrationForm(UserCreationForm):
class Meta:
model = User
fields = (
'username', 'email',
'password1', 'password2',
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields.values():
field.widget.attrs['class'] = 'form-control'
get_user_model()
によって,現在アクティブになっているユーザモデルを使用できる
なので,カスタムユーザモデルならカスタムユーザモデルで,そうでないならデフォルトのユーザモデルを使用する
また,Meta情報に`fields'を書き込まないとフォームが使えないので注意する(自分はここでしばらく悩んだ)
Viewに以下を追加する
from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.auth import get_user_model
from .forms import RegistrationForm
User = get_user_model()
"""アカウント登録ページ"""
class Registration(generic.CreateView):
model = User
template_name = 'registration.html'
form_class = RegistrationForm
success_url ='/registration/complete'
"""アカウント登録完了"""
class RegistrationComp(generic.TemplateView):
template_name = 'registration_complete.html'
アカウント登録フォームを表示するページと,登録完了用のページを準備する。
HTML作成
アカウント登録用のregistration.html'と登録完了用の
registration_complete.html'を作成し,アカウント登録画面への入り口をlogin.html
に作成する
{% extends "base.html" %}
{% block title %} TaskMan ログイン {% endblock %}
{% block mainT %} ログイン {% endblock %}
{% block mainL %}User : {{ user.get_username }}{% endblock %}
{% block auth %}
{% endblock %}
{% block body %}
<div style='padding-top: 50px;'>
<form action="" method="POST">
<div class="col-md-6 offset-md-3">
<div class="card">
<div class="card-body">
{{ form.non_field_errors }}
{% for field in form %}
{{ field }}
{{ field.errors }}
<hr>
{% endfor %}
<button type="submit" class="btn btn-lg btn-primary btn-block" >ログイン</button>
<input type="hidden" name="next" value="{{ next }}" />
{% csrf_token %}
</div>
</div>
<div class="authElement"> # 追加
<a class="btn btn-outline-secondary" href="/registration/">アカウント登録</a> # 追加
</div> # 追加
</div>
</form>
</div>
{% endblock %}
この時に,見た目を整えるためにCSSを作り適用させる
新しくstatic/css/adjustment.css
を作成する
.authElement {
margin:20px;
text-align: center;
}
このCSSを適用するために,base.html
のヘッダに追記する
<link href="{% static 'css/adjustment.css' %}" rel="stylesheet" type="text/css">
次に登録画面を作成する
<div style="padding:20px 200px 0px 200px;">
<form action="" method="POST">
{{ form.non_field_errors }}
{% for field in form %}
<div class="form-group">
<label for="{{ field.id_for_label }}">{{ field.label_tag }}</label>
{{ field }}
<span style="color:red">{{ field.errors }}<span>
</div>
{% endfor %}
{% csrf_token %}
<button type="submit" class="btn btn-primary btn-lg">登録</button>
</form>
</div>
そして、登録完了画面を作成
<div style="text-align: center; padding-top: 50px;">
<h2 >登録が完了しました</h2>
<a class="nav-link" href="/login/">ログイン</a>
</div>
登録処理が完成
画面で確認するとこうなる
アカウント登録が正常にできていることが確認できた
今回のまとめ
今回は導入したかったログイン関係とアカウント登録の作成ができた。しかし,パスワード変更ができないなどまだ課題は残っているので次回はそこら辺を解決していきたい。
シリーズ
・Djangoでタスク管理アプリをつくりたい! 環境構築編
・Djangoでタスク管理アプリをつくりたい! ユーザ認証編
・Djangoでタスク管理アプリをつくりたい! ユーザ情報編
・Djangoでタスク管理アプリをつくりたい! プロジェクト管理編
・Djangoでタスク管理アプリをつくりたい! タスク管理編1
追記
(2018/11/12)
@khskさん 誤字の指摘・修正ありがとうございます。