django006#登録ページを作ってみよう

#前回まで
ちょっと短いがHeaderの入れ方が簡単に紹介しました。
今回はRegister(登録)を作りたいと思います。これからDjangoのUser Objectを使います。

#流れ
1. User Objectはなに？
2. register.html画面を作る
3. view.pyにregisterを追加する
4. urls.pyに登録画面とLINKさせる
5. なんでなにもないんだ？Post Methodを作る
6. Redirectを作る
7. Adminページを入ってみる

##User Objectはなに？
本当だというとUser Objectを使うというよりDjangoの認証システムを使うのことです。User Objectはこの認証システムのメインで、これを使えUser登録、Login、Logout、Profilesなどの機能を自分のサイドに入れることができます。
その中に一番えらいのは'superusers' か、admin系のUserになります。

userのDefaultにはこのような属性を持っています：

* username
    * 必要です。150文字以内で_, @, +, . , -が使えます。
* password
    * もちろん、必要です。
* email
    * オプション。
* first_name
    * オプション。30文字以内。
* last_name 
    * オプション。30文字以内。

Passwordを少しだけ詳しく見ましょう。
ドキュメントによりますと、DjangoにはPasswordをこのように保存します。これはらはPasswordのコンポーネントで、$マックで区別します。

```
<algorithm>$<iterations>$<salt>$<hash>
```
* <algorithm>Hashingのアルゴリズム、1Way Hashingが使われています。
* <iterations>アルゴリズムが何回の繰り返し(Work Factor)
* <salt> random salt　 random seed
* <hash>結果　

Default値ではPBKDF2 algorithm with a SHA256 hash。場合によってアルゴリズムを変えることもできます。が、普通の場合は変える必要がありません。って…感じですね。うん。豆知識ですが、客に聞かれるかもしれないので、頭の隅に入れておきます！でもAdminのPageにLoginしPasswordをみたら、
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/b603bfc9-6ba0-d9ad-6e14-5d1ec3f2620d.png)
なんか似てますね！

DjangoのShellでUser Modelsどんなものが入ってるか見てみよう。
Python3 mange.py shell
Line3:UserをImportします
Line4:User中にあるDirを表示します。
これでdjangoから色々な機能も事前に作ってくれたことがわかりますね～
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/c33c274b-8192-c33b-a034-930236f4d8aa.png)
##register.htmlを作る

HTMLに関しては詳しく書きませんが、ここはサーバからform.as_pをもらいますね～

```
{% extends "helloworld/header.html" %}
{% block content %}
	<form method="POST">
	{% csrf_token %}
	{{ form.as_p }}

	<button type="submit">Register</button>

	if you are already had a account,please <strong><a href="/login"></a>log in</strong>.

{% endblock%}}
```
###csrf_tokenはなんなの？
CSRFは簡単にCross Site Request Forgeriesから守ることができます。この攻撃はFrom Button、Linkがある、もしくはJavascriptからなにかの動きがあるのWEBSITEに発生する、とか？
それに、ほかの人の認証を使ってLogingすることも防止できます？うんうん…よくわかりませんが、あとでWIKI先生に聞きます。

### .as_pとはなに？
HTML Form出力するとオプションをつけることができます。

* as_p
    * <p>Tagsを含めて返しします
* as_ul
    * <li>Tagsを含めて返しします。(ul　Tagsが含めてません)
* as_table
    * HTMLのTableにように返しします。

##view.pyにregisterを追加する
register.html が追加したら次、view.pyとこの子にリンクさせます。

```
from django.shortcuts import render
from django.http import HttpResponse
from .models import mydb
from django.contrib.auth.forms import UserCreationForm

# Create your views here.
def homepage(request):
	return render(
		request=request
		,template_name="helloworld/home.html"
		,context={"mydb":mydb.objects.all}
		)
def register(request):

	form =UserCreationForm

	return render(
		request=request
		,template_name="helloworld/register.html"
		,context={"form":form}
		)
```

###今度またUserCreationFormを見てみましょう。

UserCreationFormは三つのFields、username、password1、password2になります。
このClassはpassword1とpassword2   を一致してるかどうかを比べて、
validate_password()で二つのPasswordを比べる。

* validate_password(password, user=None, password_validators=None)
    * Passwordが有効か無効かを判断し、もしPasswordが有効ならNoneが返しし、無効ならばPasswordが拒否し、ValidationErrorが起こし、エラーメッセージがに返す,set_password() でPasswordを設定する。
* set_password(raw_password)
    * Raw文字列でUser Passwordを設定し、Password Hashingの関係でUser Objectが保存しません。もしRaw PasswordはNoneのであれば、パスワードはset_unusable_password()で使用不可になります。
* set_unusable_password()
    * Userをパスワード無しにマックします。それは空の文字列と違うことが注意してください。このUserにcheck_password()に使っても永遠にTrueになりません。

##urls.pyに登録画面とLINKさせる

先view.pyに追加したregister()をここに入れます。

```
from django.urls import path
from . import views

app_name="main"

urlpatterns = [
	path("",views.homepage,name="homepage")
	,path("register/",views.register,name="register")
]
```
いまはとりあえず登録Formが見えますね～
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/7348235b-c9a9-a664-1612-f04ce70bd238.png)
なにも入力されてない状態で“Register”を押すと、怒られましたね～
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/e2d8ce5f-6ccf-7f25-187c-341255cbad14.png)
ではなに入力して“Register”を押してみますね～
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/5a0a6a4b-dadf-e25c-ba50-91761ad52e7c.png)
が…反応がない？！というか戻ったみたいね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/dbc8620e-0503-8725-2040-e7e8fdf27b6a.png)
##なんでなにもないんだ？
Terminalからみると、あ、なるほど、確かにButtonは“POST”なんですね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/3b8447b0-468f-a135-3e01-9dc840d9e0b7.png)
ではPostのコードも入れておきますね。
流れはこんな感じですね：
まずlogin,logoutなどをImportします
もしrequestはPostのなら新しいUserを作る
もしformが有効であれば、DBに保存し、Logingします。
もしformが無効であればエラーメッセージをPrintします。
って感じですね。

```
from django.shortcuts import render
from django.http import HttpResponse
from .models import mydb
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login,logout,authenticate

# Create your views here.
def homepage(request):
	return render(
		request=request
		,template_name="helloworld/home.html"
		,context={"mydb":mydb.objects.all}
		)

def register(request):

	if request.method == "POST":
		form=UserCreationForm(request.POST)
		if form.is_valid():
			useer=form.save()
			login(request,user)
		else:
			for msg in form.error_messages:
				print(form.error_messages[msg])


	form =UserCreationForm

	return render(
		request=request
		,template_name="helloworld/register.html"
		,context={"form":form}

		)
```

##Redirectを作る
でもやっばりUserが作ったらまた同じのRegisterのページに戻るのは変ですよねー
普通は登録成功したらMainのページに戻ったりとかするのね。
じゃそうしましょう。ここで使うのはredirect()です。

```
from django.shortcuts import render,redirect
from django.http import HttpResponse
from .models import Tutorial
from django.contrib.auth.forms import UserCreationForm	
from django.contrib.auth import login,logout,authenticate

# Create your views here.


def homepage(request):
	return render(
		request=request
		,template_name="main/home.html"
		,context={"tutorials":Tutorial.objects.all}
		)

def register(request):

	if request.method == "POST":
		form=UserCreationForm(request.POST)
		if form.is_valid():
			user=form.save()
			login(request,user)
			return redirect("main:homepage")
		else:
			for msg in form.error_messages:
				print(form.error_messages[msg])


	form = UserCreationForm
	return render(request
		,"main/register.html"
		,context={"form":form}
		)

```

これでいける！はずだと思いますが、うん？これはなんだ？私のhelloworldが登録されたnamespaceではない？？
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/d502547b-4b35-c7b3-955c-3a3103db3ed2.png)
色々調べたら、urls.pyの中にapp_name=”helloworld”を追加すればOK。

```
from django.contrib import admin
from django.urls import path
from . import views

app_name="helloworld"

urlpatterns = [
    path('',views.homepage,name='homepage')
    ,path('register/',views.register,name='register')
]
```
それでOK！

##Adminページを入ってみる
では普通のUserをAdmin PageにLogin してみよう。
うん、権限不足だとWarningされますね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/53d11cab-9775-a7ff-29c0-e357dec04fcf.png)