diadia

興味があることをやってみる。自分のメモを残しておきます。

ユーザ登録(sign up)機能を作る

どうやってユーザを作成するか。
とりあえず作り方のアプローチとしては2通りある。
djangoビルトインのUserCreationFormを使う方法
Djangoの認証システムを使用する | Django documentation | Django

forms.pyから作成する方法(自作)



自作する方法を前半で、ビルトインのUserCreationFormを後半に記す。
注意:この方法ではuserのパスワードを保存できるかまだ確認中。userのパスワードを確実に保存したいのであればビルトインのUserCreationFormを使う方法をおすすめする。 


Djangoの認証システムを使用する | Django documentation | Django
この辺が必要になる。

views.pyにて

User = get_user_model()

def register_page():
    form = RegisterForm(request.POST)
    context = {"forms":form}
    
    if form.is_valid():
        print(form.cleaned_data)
        username = form.cleaned_data.get("username")
        email = form.cleaned_data.get("email")
        password = form.cleaned_data.get("password")
    new_user = User.objects.create_user(username, email,password )
    render(request, "register_page.html", context)

get_user_model()は使うことが推奨されている。

forms.py

from django import forms

class RegisterForm(foms.Form): 
    username = forms.CharField()
    email = forms.CharField()
    password = forms.CharField(widget=forms.PasswordInput)    
    password2=forms.CharField(
              label="ConfirmPassword",
              widget=forms.PasswordInput
                )
#フォームには入力ミス(バリデーションエラー)を表示させる機能を書く
#入力ミスの種類には、2箇所のパスワード入力値が不一致の場合に知らせるもの、すでに登録されているusername,emailの場合登録できないと知らせるものがある。

#password 不一致のバリデーション
    def match_password(self):
        data = self.cleaned_data.
        password = data.get("password")
        password2 = data.get("password2")
        if password != password2 :
            raise ValidationError("password must be same" )
        return data

#既登録の入力値エラー
    def double_email(self):
        email = self.cleaned_data.get("email")
        query_set = User.objects.filter(email=email)
        if email = query_set:
            return ValidationError("this e-mail is taken")
        return email

    def double_email(self):
        username = self.cleaned_data.get("username")
        query_set = User.objects.filter(username=username)
        if username = query_set:
            return ValidationError("this username is taken")
        return username

簡単にまとめると、登録機能はviews.pyが担っている。一方、forms.pyは入力内容を決めている。また入力値が適正かの判断もforms.pyが担っている。
登録機能の要views.pyについて少し書く。
create_user()で登録させる。引数はusername,email,passwordにした。
new_user = User.objects.create_user(username, email, password) のUserについては予め定義しておく。
User = get_user_model() これをしておかないと、djangoの既設定Userをつかってしまうからっぽい。username, email, passwordはいつもどおりに取り出す。(POSTの値をcleaned_dataして辞書型のデータに整形し、get()にキーを入力して取り出すって流れ。)




UserCreationFormを使う方法
既存のUserモデルを使ってsign up機能を実装するにはUserCreationFormを用いると良いと思っている。それはユーザーのパスワードを確実に登録できるからだ。
password = request.POST.get("password") や password = form.cleaned_data.get("password")と設定した変数passwordを扱ってuserをcreateすることが経験上うまくいかなかったからだ。単純に勘違いの可能性もあるが、今はpasswordの変数を使わないでuserインスタンスを発行するのが望ましいと結論づけている。
passwordの変数を使わないでuserインスタンスを発行するとは、User.objects.create_user(****)やUser.objects.create(****)を使わないでユーザーを作るということだ。
どうやらdjangoではuserモデルに関わるものはすでにいろいろなプログラムが準備されており、そのプログラムがあることでDjangoユーザーは自分の思い通りにコードを書くことができない。djangoを思い通りに使いたい場合にはUserモデル周辺の仕組みがどうなっているかを理解していくことが重要だと認識するようになった。

参考
https://simpleisbetterthancomplex.com/tutorial/2017/02/18/how-to-create-user-sign-up-view.html
https://overiq.com/django/1.10/django-creating-users-using-usercreationform/

https://docs.djangoproject.com/ja/2.1/topics/auth/passwords/

from django.shortcuts import render
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import login, authenticate




def home(request):
	if request.method == "POST":
		form = UserCreationForm(request.POST)
		if form.is_valid():
			form.save()
#新事実!form.save()した段階でuserインスタンスが作成されている!!!
#以下のコードは登録した後に自動でログインする仕組みを書いているに過ぎない。
			username = form.cleaned_data.get("username")
			password = form.cleaned_data.get("password1")
			new_user = authenticate(username=username, password=password)
			login(request, new_user)			
			print(request.user.id, request.user)
			
			return render(request, "accounts/success.html")


	form =UserCreationForm()
	context = {"forms":form}
	return render(request, "accounts/home.html", context)

とにかくdjangoが準備したUserCreationFormにユーザーネームやらパスワードを入力したあとにUserCreationFormのインスタンスメソッドsave()すれば良い。create,create_userは使わなくて良い。
あとこれは想像だけれどもパスワードを登録するときには、文字列型の状態だと登録ができないのではないか?
パスワードを登録する際に$$$のような形で登録しないとうまく保存されないような気がする。入力したパスワードの文字列型からこの形に変換してくれる機能をUserCreationFormは有していると思われる。