django#008_loginとlogout

#前回まで
前回はtemplatesの中に綺麗にしましたし、POP-UPメッセージも表示させました。ようやくLoginとLogoutについて書きます！
これは始まる前のFileの構成は前回と変わらないです。これは始まる前のFileの構成は前回と変わらないです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/7686ac10-1dcf-2425-6038-49e2a7ad7f3f.png)
#流れ
* views.pyで/login のFunctionを作る
* urls.pyでloginのurl pathを入れる
* login.htmlをtemplatesに追加
* navbar.htmlを修正する
* views,pyで/logoutのFunctionを作る
* urls.pyでlogoutのurl pathを入れる
* 自分のlogin formを作ってみる
* Admin Pageをみてみる

##views.pyで/login のFunctionを作る

流れはこんな感じですね。
もらったリクエストはPOSTかどうかをCHECKします。
もしPOSTでなければ、AuthenticationFormを返しします。
もしPOSTならUserからLoginをしようとしてるとわかってます。
formが有効かどうかを判断します。
もし無効なら、エラーメッセージを返しします。
もし有効なら認証を行います。
認証の結果は無効ならエラーメッセージを返しします。
認証の結果が有効ならLoginし、メッセージ返し、HomeにRedirectしますって感じですね。

```
form=AuthenticationForm(request,request.POST)
class AuthenticationForm
```

このFormはUserのLogin用のためです。
１個目のArgumentはRequestで、なのでrequestをそのままに渡しします。
１個目Formの内容です。

```
	user=authenticate(username=username,password=password)	
```

>authenticate(request=None, **credentials)
このメソッドを使って認証を行います、認証されるデータセットのはcredentialsに渡しします。
CredentialsはのKeyword　Argumentsは2つがあり、Usernameとpasswordです。もう認証okならUser Objectが返してくれます。

```
if user is not None:
　#
```
なので、認証終わったらあとNoneかどうかを比較するのはその原因です。もしNoneじゃなければ→User Objectがあります→認証OKってことです。
このメソッドを使えばUser Logiすることができます。必要な引数はrequest, userです。
login()を使うことよってDjango SessionでUserIDを保存します。
全体的はこんな感じですね～

```
def login_request(request):
	if request.method=="POST":
		form=AuthenticationForm(request,request.POST)
		if form.is_valid():
			username=form.cleaned_data.get('username')
			password=form.cleaned_data.get('password')
			user=authenticate(username=username
							 ,password=password	
				)
			if user is not None:
				messages.info(request,'Welcome Back,{}.'.format(username))
				login(request,user)
				return redirect('helloworld:homepage')
			else:
				messages.error(request,'some error{}.'.format(form.error_messages))
		else:
			messages.error(request,'some error{}.'.format(form.error_messages))

	form=AuthenticationForm()
	return render(request
		,"helloworld/login.html"
		,{"form":form}
		)
```

## urls.pyでloginのurl pathを入れる

ここはもう説明しなくてもわかりると思いますー

```
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')
    ,path('login/',views.login_request,name='login')
]
```

## login.htmlをtemplatesに追加
Fileの構成はこうになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/30e93432-925c-5628-c7d6-bc806e6e75a9.png)

コードは以下です：

```
{% extends "helloworld/header.html" %}


{% block content %}
	<form method="POST">
	{% csrf_token %}
	{{ form.as_p }}

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

	if you do not had a account,please <strong><a href="/login"></a>Register</strong>.

{% endblock%}}
```
## navbar.htmlを修正する
Loginもし成功したらNav barがまだLoginが表示されるのはおかしいですよね～ここでもしLoginがOKならUser名を表示するようにします。
もしLoginしたら　Home　Username　Logout
もしLoginしてないなら　Home Register Login

```
  <nav>
    <div class="w3-bar w3-border w3-light-grey">
    	<a href="/" class="w3-bar-item w3-button w3-mobile">Home</a>
    	{% if user.is_authenticated %}
    		 <a href="/account" class="w3-bar-item w3-button w3-mobile">{{user.username}}</a>
    		 <a href="/logout" class="w3-bar-item w3-button w3-mobile">logout</a>
    	{% else %}
        	<a href="/register" class="w3-bar-item w3-button w3-mobile">Register</a>
        	<a href="/login" class="w3-bar-item w3-button w3-mobile">Login</a>
        {% endif%}
        
    </div>
  </nav>
```

Loginしたら…OKですね！Redirectしましたし、Usernameもちゃんと表示されましたね。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/c5401c5f-c5c5-953f-fe53-ebc152d30c35.png)

## views.pyで/logoutのFunctionを作る

ここで使われてるのはlogout()です。
流れはこんな感じです：
logoutします。
Message表示します。
Homeに戻ります。

```
def logout_request(request):
	logout(request)
	messages.info(request,"Logged out,please come back again.")
	return redirect('helloworld:homepage')
```
>
logout(request)
Log InされたUserをLog outさせます。引数はHttpRequestだけ、戻り値がありません。

## urls.pyでlogoutのurl pathを入れる
ここはもう説明しなくてもわかりると思いますー

```
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')
    ,path('login/',views.login_request,name='login')
    ,path('logout/',views.logout_request,name='logout')
]
```
Logoutしてみたら…OKですね！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/5ac4aaea-81c4-0fd2-8296-000b750d0301.png)

## 自分のlogin formを作ってみる
では自分のloginformも作ってみよう！まずforms.pyを追加しますー。
その中にメールアドレスも必ず入力しないとだめようにします。
File構成はこうになりましたね！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/94e1d0c3-a6b9-8eb4-f513-33067aa12f3b.png)

流れとしては...
新しいFrom Classを作ります。
EmailFieldを入力必要項目として作ります。
Meta　Classを作ります。
Fieldsはどんな項目いるのかを設定します。
saveメソッドを作ります。
save()が呼びされたときまず一旦Commitをやめます。
user.emailにFormの中に入力されたものを入れます。
Commitします。

### 次はsaveされた実際どんなものが走ってるの？

1. pre-save signalをだします。そのsignalが送ったあと、全てこのsignalを待ってるFunctionも生かしなにかの動作します。
2. Preprocess the data。Fields のpre_save()がCallされ、自動的にデータを処理します。
3. databaseに送るデータを準備する。Fields のget_db_prep_save()メソッドがデータの現在値をDatabaseに書き込めるのデータタイプに変更する。
4. 普通のFieldsが大体そういうデータの準備がいらないです。例えば整数、文字列などもう既にDatabaseに書き込むの“準備“ができました。ですが、普通なデータタイプならそういう先処理が必要です。例えばDateFieldはPythonのdatetime objectsを使ってデータを保存する。DatebaseはPythonのdatetime objectsを保存することができないのでISO-compliant date stringに変換する作業が必要になります。
5. 次はデータをDatabaseに挿入します。
6. 最後はpost-save signalを出します。すべてのこのsignalを待ってるFunctionを生かしなにかの動作します。
その中のメソッドとかも深すぎるのでここでもう説明しません…私みてもてもわかりません。

```
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User

class newUserFrom(UserCreationForm):
	email=forms.EmailField(required=True)

	class Meta:

		model=User
		fields=('username','email','password1','password2')

	def save(self,commit=False):
		user=super(newUserFrom,self).save(commit=False)
		user.email=self.clean_data['email']
		if commit:
			user.save()
		return user
```

Email　Fieldsが増えましたね！

![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/67d66d7a-2932-411f-6e5d-6100c78a6f9a.png)
Admin PageでCheckしてみたら、ちゃんとメールアドレスがついてますね！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/154661/5f3bd300-7619-bd45-8b96-9fe706a15f9f.png)