djangoでログイン画面を実装する

最近、仕事でdjangoを触るようになりました。（初心者です）
先日、ログイン画面の実装をしている際に、まってしまったので、メモしておきます。
気づいてしまえば、かなり簡単ですね。。。

django 2.0.6を使用します。

https://it-engineer-lab.com/archives/544
がとても参考になりました。ありがとうございます。
# 設定
djangoはなんでもできるフレームワークで、ログインとかもauthに対応したクラスを提供してくれています。
今回は、以下のような構造を仮定して話を進めます。

```markdown:architecture
- my_app
    - my_app
        - __init__.py
        - settings.py
        - urls.py
        - wsgi.py
    - app
        - config
        - migrations
        - models
            - __init__.py
            - users.py
        - templates
            - regstration
                - login.html
            - index.html
        - tests
        - view.py
        - __init__.py
        - admin.py
        - urls.py
```

# やったこと
* テンプレートのパスと、UserModelの追加

```python:settings.py
AUTH_USER_MODEL = 'my_app.User' # 追加
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',
            ],
        },
    },
]
```

AUTH_USER_MODELに独自のUserモデルを指定します。
あと、テンプレートのパスを追加
今風に書くなら、pathlib使って書くんでしょうかね。

* モデルの書き換え

```python:users.py
from django.contrib.auth.base_user import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.validators import UnicodeUsernameValidator
from django.core.mail import send_mail
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _

# 必要なら、user_managerを独立させてimport 

class User(AbstractBaseUser, PermissionsMixin)
    username_validator = UnicodeUsernameValidator()
    username = models.CharField(_('user name'), ....)

    # 必要なカラムを追加

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')
        db_table = 'users'

    def clean(self):
        super().clean()
        self.email = self.__class__.objects.normalize_email(self.email)

    def email_user(self, subject, message, from_email=None, **kwargs):
        """Send an email to this user."""
        send_mail(subject, message, from_email, [self.email], **kwargs)


```
この辺は、ほとんどdjango.contrib.auth.base_user.AbstractUserと同じです。
どちらを使う方がいいかとかについては、以下が詳しいです。
- https://qiita.com/okoppe8/items/10ae61808dc3056f9c8e
- https://qiita.com/NAKKA-K/items/7627b6a22f364941b989
- http://nihaoshijie.hatenadiary.jp/entry/2014/06/11/165258

* my_app/urls.pyを編集

```python:my_app/urls.py
from django.conf.urls import url, include

urlpatterns = [
    url(r'^', include('app.urls')),
    url(r'accounts/', include('django.contrib.auth.urls')),
]
```
accountsにしなくてもいいかなとは思います。

* login.htmlをコピペ

djangoに参考htmlがあるので、とりあえず使用
https://docs.djangoproject.com/ja/2.0/topics/auth/default/#all-authentication-views

必要なのは、extendsのところを自分用に書き換えること

ディレクトリをregistrationにしましたが、モデルの編集時にtemplate_nameをカスタマイズすれば使える（はず）

```django:templates/registration/login.html
{% extends "base.html" %}

{% block content %}

{% 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>

{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>

{% endblock %}
```

なんかもっとこうした方がいいとか、これが足りないとかあったら教えてください。