Djangoでログイン処理を作る


[Djangoのチュートリアル](https://docs.djangoproject.com/ja/1.10/intro/)にはログイン処理に関する記載がないので補足的に書いてみる。
(認証に関するドキュメントは[ある](https://docs.djangoproject.com/ja/1.10/topics/auth/)が入門者向けではない感じ)

Djangoのバージョンは1.10

# accounts アプリ作成

今回はサイト内にログイン/ログアウト専用のアプリacocuntsを作成する。
accountsという名前にしたのは`sessings.LOGIN_URL`のデフォルト値が`/accounts/login`になっているため。

```bash
$ python manage.py startapp accounts
```

pollsのときと同様にアプリの登録を行う

```py3:mysite/settings.py
INSTALLED_APPS = [
    'polls.apps.PollsConfig',
    'accounts.apps.Accountsconfig', # 追加
    #...
]
```

# URL設定

mysite/urls.pyを編集

```py3:mysite/urls.py
urlpatterns = [
    #...
    url(r'accounts/', include('accounts.urls')), # 追加
]
```

accounts/urls.pyを新規作成
ここではデフォルトで用意されているlogin/logoutビューを使用する

```py3:accounts/urls.py
from django.conf.urls import url
from django.contrib.auth.views import login,logout

urlpatterns = [
    url(r'^login/$', login,
        {'template_name': 'accounts/login.html'},
        name='login'),
    url(r'^logout/$', logout, name='logout')
]
```

Django1.10から

```py3
url(r'^login/$', 'django.contrib.auth.views.login')
```

のような文字列指定はできなくなっているので注意

# Template作成

```jinja:accounts/templates/accounts/login.html
{% extends "admin/base.html" %} {# ① #}

{% block content %}

{% if form.errors  %}
  <div class="alert alert-danger" role="alert">
    <p>Your usernamne and password didn't match. Please try again.</p>
  </div>
{% endif %}

<div class="panel panel-primary">
  <div class="panel-heading">
    <h3 class="panel-title text-center">Log-in to mysite</h3>
  </div>
  <div class="panel-body">
    <form action="{% url 'login' %}" method="post" role="form">
      {% csrf_token %}
      <div class="input-group" style="margin-bottom:10px">
        <span class="input-group-addon"><i class="fa fa-user fa-fw"></i></span>
        <input id="id_username" name="username" type="text" value="" maxlength="256" placeholder="Username" aria-describedby="sizing-addon1" autofocus required/> {# ② #}
      </div>
      <div class="input-group" style="margin-bottom:10px">
        <span class="input-group-addon"><i class="fa fa-lock fa-fw"></i></span>
        <input id="id_password" name="password" type="password" value="" maxlength="256" placeholder="Pasword" aria-describedby="sizing-addon1" required/> {# ② #}
      </div>

      <button type="submit" style="margin-bottom:-20px"><i class="fa fa-sign-in">Login</i></button>
      <input name="next" type="hidden" value="{{ next }}"/> {# ③ #}
    </form>
  </div>
</div>
{% endblock %}
```

① 楽するためにadminのbase.htmlを拝借
② `django.contrib.auth.view.login`はデフォルトで`AuthenticationForm`を利用している。`AuthenticationForm`は"username","password"と名前のついたフォームの値を利用する
③ ログイン画面にリダイレクトされた場合リダレクト元は`/accounts/login/?next=/polls/3`のように渡される。このnextの値を`AuthenticationForm`に通知する必要がある


ログアウトのページはadminのものをそのまま使用するため、今回は作成しない。


# 試してみる

```py3:polls/views.py
# ...
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

@method_decorator(login_required, name='dispatch')
class IndexView(generic.ListView):
    # ...
```

クラスベースビューのため、`@method_decorator`を使用している。関数の場合は`@login_required`でOK。

http://localhost:8000/polls にアクセスすると以下の画面がでる。

![django_login.png](https://qiita-image-store.s3.amazonaws.com/0/39647/193082c3-2aef-6723-3ba7-9e869695260d.png)

superuserのアカウントでログインできるはずである。

以前adminにログインしているとログイン画面にならないことがあるため、その場合は http://localhost:8000/accounts/logout にアクセスして一度ログアウトする必要がある。