前置き
独学で、子供の成長アプリを作った時のことを、記録として残していきます。
間違っているところなどあれば、ご連絡お願いします。
①Djangoのようこそページへたどり着くまで
②NginxでDjangoのようこそページへたどり着くまで
③カスタムユーザーを作ってadminにたどり着く
④ログインログアウトをしよう <--ここです
⑤ユーザー登録(サインイン)機能を作ろう
⑥ユーザーごとのデータ登録できるようにする〜CRU編
⑦ユーザーごとのデータ登録できるようにする〜削除編
⑧画像ファイルのアップロード
⑨身長体重を記録する@一括削除機能つき
⑩成長曲線グラフを描いてみよう
⑪本番環境へデプロイ+色々手直し
Goal
ログインログオフ機能を作ろう
HTML(下準備)
Djangoのtemplateをアプリごとに分けるのが面倒になりそうなので、
テンプレートは一箇所に置くことにする。最終形は以下(細かいものは省略)。
.
├── docker-compose.yml
├── nginx
│ ├── conf
│ │ └── mysite_nginx.conf
│ └── uwsgi_params
├── src
│ ├── manage.py
│ ├── mysite
│ │ ├── settings.py
│ │ ├── urls.py
│ │ └── wsgi.py
│ ├── templates
│ │ ├── base.html
│ │ └── users
│ │ ├── login.html
│ │ ├── mypage.html
│ │ └── signup.html
│ └── users
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── models.py
│ ├── urls.py
│ └── views.py
├── static
│ └── 略
└── web
├── Dockerfile
└── requirements.txt
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',
],
},
},
]
CSSはbootstrapが手っ取り早くて良い。
bootstrapはdjango用のものがあるので、それを使う。
Django==2.2.2
psycopg2==2.8.4
uwsgi==2.0.17
django-bootstrap4==1.1.1 #追加
settingはAPPSに追加するのと、Templateの指定にも追加する。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users.apps.UsersConfig',
'bootstrap4', #追加
]
(略)
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',
],
'builtins':[ #追加
'bootstrap4.templatetags.bootstrap4',
],
},
},
]
HTML(本番)
ベースのHTML。bootstrapでレスポンシブ対応ぽくしている。
{% load static %}
{% bootstrap_css %}
{% bootstrap_javascript jquery='full' %}
<html>
<head>
<title>kids Growth</title>
<link rel="stylesheet" href="{% static 'css/kidsGrowth.css' %}">
{% block extra_js %}{% endblock %}
</head>
<body>
<!-- Navigation -->
<nav class="navbar navbar-expand-sm navbar-dark bg-dark mt-3 mb-3">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav4" aria-controls="navbarNav4" aria-expanded="false" aria-label="Toggle navigation">
<span class="sr-only">メニュー</span>
<span class="navbar-toggler-icon"></span>
</button>
<a class="navbar-brand" href="">Kids Growth</a>
<div class="collapse navbar-collapse" id="navbarNav4">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="">メニュー1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">メニュー2</a>
</li>
<li class="nav-item">
<a class="nav-link" href="">メニュー3</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{% url 'users:mypage'%}">マイページ</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" href="{% url 'users:logout'%}">ログアウト</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" href="{% url 'users:login'%}">ログイン</a>
</li>
{% endif %}
</ul>
</div>
</nav>
<div class="content container">
{% block content %}
{% endblock %}
</div>
</body>
</html>
マイページ。(ユーザー名が出るだけ)
ログイン後に飛んでくるところとして指定。
{{ user }}はあとでViewから引き渡します。
{% extends 'base.html' %}
{% block content %}
<div class="col-md-12 col-lg-5">
<h2>My Page</h2>
<br>
<br>
<table class = "table">
<tr>
<td>ユーザー名</td>
<td>{{ user }}</td>
</tr>
</table>
</div>
{% endblock content %}
formという名前でフォームを引き渡して、
bootstrap_formで綺麗に整形するだけ。
ユーザー登録のリンクを用意してますが、その機能は次で。
{% extends 'base.html' %}
{% block content %}
{{ form.media }}
<div class="col-md-12 col-lg-5">
<h2>Login</h2>
<form action="" method="POST">
{{ form.non_field_errors }}
{% bootstrap_form form %}
<hr>
<button type="submit" class="btn btn-success btn-lg btn-block" >ログイン</button>
{% csrf_token %}
</form>
<a href="{% url 'users:signup' %}">ユーザー登録</a>
</div>
{% endblock %}
Form
FormとしてAuthenticationFormを継承することで、
ログイン機能を実装します。これだけ。便利。
class LoginForm(AuthenticationForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
View
ログインとログアウトは専用のViewがあるので継承する。
@login_requiredを指定した関数はログインした状態じゃないと呼ばれない。
ひとまずはログインしているユーザーの名前を取得して、templateに返すだけのお仕事。
ちなみにログインのクラスをloginにすると、このあとSignup関数を作るときに
規定のネーミングとバッティングするのかエラーが外れず、ややカッコ悪いネーミング。
from .forms import LoginForm
from django.shortcuts import render, redirect
from django.contrib.auth.views import LoginView, LogoutView
from django.contrib.auth.decorators import login_required
#ログイン
class login_mypage(LoginView):
form_class = LoginForm
template_name = 'users/login.html'
#ログアウト
class logout(LogoutView):
template_name = 'users/login.html'
#マイページ
@login_required
def mypage(request):
user_name = request.user
params = {
'user' : user_name,
}
return render(request, 'users/mypage.html',params)
urls
プロジェクトのurlsで、アプリごとのurlsを読み込む。
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('users.urls')),
]
アプリごとに定義したURLパターンごとにViewを決める。
app_name = 'users'
urlpatterns = [
path('', views.mypage, name='mypage'),
path('mypage/', views.mypage, name='mypage'),
path('login/', views.login_mypage.as_view(), name='login'),
path('logout/', views.logout.as_view(), name='logout'),
]
Setting.py
以下を追加する。ログインするときのURLはここだよ〜
ログインしたらここに最初にアクセスしてね〜
ログアウトしたらなんの画面を見せるよ〜
ということを決める。
LOGIN_URL = 'users:login'
LOGIN_REDIRECT_URL = 'users:mypage'
LOGOUT_REDIRECT_URL = 'users:login'
出来上がり
ログイン画面と、ログインした後の画面。