【 Docker＋Nginx＋Django＋RDS】WEBアプリができるまで⑤ユーザー登録（サインイン）機能を作ろう

# 前置き
独学で、子供の成長アプリを作った時のことを、記録として残していきます。
間違っているところなどあれば、ご連絡お願いします。
　①[Djangoのようこそページへたどり着くまで](https://qiita.com/quantity82/items/e8c2392bf982efb55f80)
　②[NginxでDjangoのようこそページへたどり着くまで](https://qiita.com/quantity82/items/88a6348135e25c661feb)
　③[カスタムユーザーを作ってadminにたどり着く](https://qiita.com/quantity82/items/b3cd6ded5bbb5f3726f3)
　④[ログインログアウトをしよう](https://qiita.com/quantity82/items/8e4b7ce2ef56e60ad392)
　⑤[ユーザー登録（サインイン）機能を作ろう](https://qiita.com/quantity82/items/bbfc7e72d4a65c71e24c)　<--ここです
　⑥[ユーザーごとのデータ登録できるようにする〜CRU編](https://qiita.com/quantity82/items/4d019a4ee475208a5a26)
　⑦[ユーザーごとのデータ登録できるようにする〜削除編](https://qiita.com/quantity82/items/c48fee71b5f8eb766dae)
　⑧[画像ファイルのアップロード](https://qiita.com/quantity82/items/9bcbd25902f6878ee325)
　⑨[身長体重を記録する＠一括削除機能つき](https://qiita.com/quantity82/items/c8e58742eeaa8c0fc954)
　⑩[成長曲線グラフを描いてみよう](https://qiita.com/quantity82/items/619f5ed2a6cd45f7f592)
　⑪[本番環境へデプロイ＋色々手直し](https://qiita.com/quantity82/items/6e91b7ee7a2d7e0fab32)

# Goal
サインイン機能を作ろう

# Form
Djangoはログインログアウトは簡単に実装できる。（あと簡単なCRUDも）
サインインも機能は実装されているが、Templateはないので自分たちで作る。
カスタムユーザーを推奨しているし、ユーザーを管理するために欲しい情報は
ビジネスロジック寄りであるということだろう。

UserCreationFormを継承することでサインインの基本機能を継承。
Userはget_user_model()をしないとエラーになる。
カスタムユーザーにしているので、明示しないと見つからないのだと思われる。

```python:forms.py
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.forms import UserCreationForm

User = get_user_model()

class SignUpForm(UserCreationForm):
    class Meta:
        model = User
        fields = ('email',)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for field in self.fields.values():
            field.widget.attrs['class'] = 'form-control'
```

# View
HTMLからPOSTで受け取って、フォームを返す・・・という基本形。


```python:users/view.py
from django.contrib.auth import login as dj_login
from .forms import SignUpForm
from django.shortcuts import render, redirect

# サインアップ画面
def signup(request):
    if request.method == 'POST':
        form = SignUpForm(request.POST)
        if form.is_valid():
            user = form.save()
            dj_login(request, user)
            return redirect(to='/')
    else:
        form = SignUpForm()
    return render(request, 'users/signup.html', {'form': form})
```

# HTML
ログインページとあまり変わらない。Formとbootstrapに任せる。

```html:users/signup.html
{% extends 'base.html' %}

{% block content %}

<div class="col-md-12 col-lg-5">
    <h2>ユーザー登録</h2>
    <form method="POST" class="post-form">{% csrf_token %}
        {% bootstrap_form form %}
        <button type="submit" class="save btn btn-primary">登録</button>
    </form>
</div>
{% endblock %}
```

# urls
signupページのページを追加。
signupにはLoginページからリンクを貼っている。詳細は１つ前の回を参照。

```python:users/urls.py
app_name = 'users'

urlpatterns = [
    path('', views.mypage, name='mypage'),
    path('signup/', views.signup, name='signup'), #追加
    path('mypage/', views.mypage, name='mypage'),
    path('login/', views.login_mypage.as_view(), name='login'),
    path('logout/', views.logout.as_view(), name='logout'),
]
```

# 確認
Signup画面。入力のためのバリデーションコメントも付いてる。
（邪魔な場合は消せる。）
<img width="1440" alt="スクリーンショット 2020-02-11 21.05.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547363/53f563f2-3bda-69dd-5f88-a0545370ab38.png">

入力するユーザー名（メールアドレス）が重複していると、検知する。
<img width="1440" alt="スクリーンショット 2020-02-11 21.06.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547363/e6be5099-383d-d198-fbb9-dbf6756f0b65.png">

登録が成立すると、マイページに飛ぶ。
<img width="1440" alt="スクリーンショット 2020-02-11 21.06.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547363/2b26dd7f-b9ff-23fb-97b6-65aad4388421.png">