Django 認証機能を追加してみる その２

#背景
前回の記事[Django 認証機能を追加してみる その１](https://qiita.com/teijinakano/items/46aca435e741637f3530)で認証機能を使いする準備として簡単なアプリを作りました。今回をそれに認証機能を追加していきます。
[Django2 でユーザー認証（ログイン認証）を実装するチュートリアル -1- 環境構築とアプリ雛形の作成](https://it-engineer-lab.com/archives/506)　という記事が一番わかりやすそうだったので参考にさせて頂きましたが、細かいところでいまく行きませんでしたので、私の環境でうまく行った手順を書いておこうと思い立ちました。

#動作環境
CentOS Linux release 7.5.1804 (Core)
mysql  Ver 8.0.12
$ python3 -V
Python 3.6.5
django.VERSION　(2, 1, 1, 'final', 0)

#認証機能追加手順
ネットの記事を読んで行くとDjangoには標準で認証機能がついているようです。
myapp/settings.py の最後に以下を追加します。

~~~
LOGIN_REDIRECT_URL = '/'
~~~

myapp/urls.pyを以下のように変更します。

~~~
from django.conf.urls import include, url
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('accounts/', include('django.contrib.auth.urls')), #  追加
    path('admin/', admin.site.urls),
    url(r'', include('blog.urls')),
]

~~~
プロジェクト直下に templates というディレクトリを新規作成します。
myvenvは、以下のようなディレクトリ構成になります。

~~~
bin
blog
include
lib
lib64 -> lib
manage.py
myapp
templates　　<--新規作成
~~~
myapp/settings.py にtemplatesの場所を指定します。

~~~

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS':  ['./templates'],      #  ./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',
            ],
        },
    },
]
~~~
「ログイン画面」と「ログアウト画面」のテンプレートを作成します。
ログイン画面: templates/registration/login.html

~~~
{% extends "base.html" %}

{% block body %}
 
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
 
{% if next %}
    {% if user.is_authenticated %}
    <p>Your account doesn't have access to this page. To proceed,
    please login with an account that has access.</p>
    {% else %}
    <p>Please login to see this page.</p>
    {% endif %}
{% endif %}
 
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>
 
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
{% endblock %}

~~~

ログアウト画面: templates/registration/logged_out.html

~~~
ログアウトしました。 <---これだけ
~~~

仮想環境 myenv でアプリケーション accounts を作成します。

~~~
$python3 manage.py startapp accounts
~~~
myapp/settings.py にアプリを登録します。

~~~
INSTALLED_APPS = [
    'accounts.apps.AccountsConfig', # [追加]
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]
~~~
accounts/urls.py を新規作成します。

~~~
# accounts/urls.py

from django.urls import path

from . import views

# set the application namespace
# https://docs.djangoproject.com/en/2.0/intro/tutorial03/
app_name = 'accounts'

urlpatterns = [
    path('signup/', views.SignUpView.as_view(), name='signup'),
]
~~~

myapp/urls.py にaccountsの設定を追加します。

~~~
from django.conf.urls import include, url
from django.contrib import admin
from django.urls import path

urlpatterns = [
    path('accounts/', include('django.contrib.auth.urls')), #  追加
    path('accounts/', include('accounts.urls')), #  追加
    path('admin/', admin.site.urls),
    url(r'', include('blog.urls')),
]
~~~
accounts/views.py を編集します。

~~~
from django.shortcuts import render

# Create your views here
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic


class SignUpView(generic.CreateView):
    form_class = UserCreationForm
    success_url = reverse_lazy('login')
    template_name = 'accounts/signup.html'
~~~
accoutsのhtmlファイルを作成します。accounts/templates/accounts/signup.html
ディレクトリが深いので注意！

~~~
# accounts/templates/accounts/signup.html

{% extends 'base.html' %}

{% block body %}
<h1>Sign up</h1>
<section class="common-form">
    <form method="post">
        {% csrf_token %}
        {{ form.as_p }}
        <button type="submit" class="submit">Sign up</button>
    </form>
</section>
{% endblock %}
~~~
ログインしていないユーザーにアクセスできないように、views.py に定義したビュー関数の直前に @login_requiredを追加します。

~~~
$vi blog/views.py
from	django.shortcuts	import	render
from	django.contrib.auth.decorators	import	login_required　　#追加

@login_required    #追加
def	post_list(request):
return	render(request,	'blog/post_list.html',	{})
~~~
myvenv/blog/templates/blog/post_list.htmlをちょっと変更します。

~~~
<html>
    <p>こんにちは</p>
    <p>動いています！！</p>
<a href="http://127.0.0.1:8000/accounts/logout/">ログアウト</a>   <--追加
</html>
~~~



サーバーを起動します。

~~~~
$ python3 manage.py runserver
Performing system checks...

System check identified no issues (0 silenced).
May 27, 2020 - 15:14:27
Django version 2.1.1, using settings 'myapp.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
~~~~

http://127.0.0.1:8000/accounts/signup/ にアクセスしてユーザーを登録します。
![signup.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26218/0c2058c4-cbea-9116-3735-109be4deedb2.jpeg)

http://127.0.0.1:8000/　にアクセスするとlogin画面が表示されるので、先ほど作ったid,passwordでloginします。
![login.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26218/e9b0115a-6211-c4d5-e793-9d0b89933f8b.jpeg)
以下の画面が表示されます。
![hello2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26218/9e2359b9-59a3-b4b4-2e2e-ad5dc9b6ca26.jpeg)
ログアウトをクリックすると、"ログアウトしました"と表示されます。
![logout.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/26218/44ee79b8-eff3-a9de-b483-ae46748d63a0.jpeg)




#参考
以下の記事大変参考になりました。ありがとうございます。
[Django2 でユーザー認証（ログイン認証）を実装するチュートリアル -1- 環境構築とアプリ雛形の作成](https://it-engineer-lab.com/archives/506)