mizzsugar’s blog

日々感じていることや学んだことを書きます。エンジニアリング以外にも書くかもしれません。

【Python・Django入門】ログイン画面、ユーザー登録画面を作る①

ブログのユーザー登録画面と、ログイン画面を作成します。

f:id:mizzsugar:20180628205546p:plain

f:id:mizzsugar:20180628205615p:plain

投稿画面と投稿一覧画面はこの記事のものを利用します。

mizzsugar.hatenablog.com


forms.pyでログインフォームとユーザー登録フォームを定義するクラスを作成します。

ユーザー登録では、

  • ユーザー名
  • パスワード
  • メールアドレス

を入力してもらいます。

ログイン画面では、

  • ユーザー名
  • パスワード

を入力してもらいます。

forms.py

from django import forms

class RegistrationForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField()
    email = forms.EmailField()

class LoginForm(forms.Form):
    username = forms.CharField()
    password = forms.CharField()

ログインフォームとユーザー登録フォーム画面のhtmlは下記になります。 htmlファイルを保存する、templateフォルダに作成します。(templateフォルダについては、上の記事をご参照ください)

login.html

<form action="/login" enctype="multipart/form-data" method="POST">
    {% csrf_token %}
    {{ login_form }}
    <input type="submit" value="submit">
</form>

<a href="/registration">新規登録はこちら</a>

registration.html

<form action="/registration" enctype="multipart/form-data" method="POST">
    {% csrf_token %}
    {{ registration_form }}
    <input type="submit" value="submit">
</form>

ユーザー情報について、models.pyは作成しません。 views.pyにUserクラスをインポートすれば、自動でテーブルが生成されます。

import django.http
import myApp.models
import myApp.forms
from django.shortcuts import render
import uuid
from django.contrib.auth.models import User
import re
from django.contrib.auth import authenticate, login as django_login

def has_digit(text):
    if re.search("\d", text):
        return True
    return False

def has_alphabet(text):
    if re.search("[a-zA-Z]", text):
        return True
    return False


def post_new_post(request):
    if request.method == 'POST':
        form = myApp.forms.InputForm(request.POST)
        if form.is_valid():
            myApp.models.Post.objects.create(name=request.POST['name'], age=request.POST['age'], comment=request.POST['comment'])
            return django.http.HttpResponseRedirect('/list')
    else:
        form = myApp.forms.InputForm()
    return render(request, 'post_new_post.html', {'form': form})

def list(request):
    posts = myApp.models.Post.objects.all()
    return render(request, 'list.html', {'posts': posts}) 

def login_user(request):
    if request.method == 'POST':
        login_form = myApp.forms.LoginForm(request.POST)
        username = login_form.username
        password = login_form.password
        user = authenticate(request, username=username, password=password)
        if user is not None:
            django_login(request, user)
            return django.http.HttpResponseRedirect('/new_post')
        else:
            login_form.add_error(None, "ユーザー名またはパスワードが異なります。")
            return render(request, 'login.html', {'login_form': login_form})
        return render(request, 'login.html', {'login_form': login_form})
    else:
        login_form = myApp.forms.LoginForm()
    return render(request, 'login.html', {'login_form': login_form})
    #アカウントとパスワードが合致したら、その人専用の投稿画面に遷移する
    #アカウントとパスワードが合致しなかったら、エラーメッセージ付きのログイン画面に遷移する
    

def registation_user(request):
    if request.method == 'POST':
        registration_form = myApp.forms.RegistrationForm(request.POST)
        password = request.POST['password']
        if len(password) < 8:
            registration_form.add_error('password', "文字数が8文字未満です。")
        if not has_digit(password):
            registration_form.add_error('password',"数字が含まれていません")
        if not has_alphabet(password):
            registration_form.add_error('password',"アルファベットが含まれていません")
        if registration_form.has_error('password'):
            return render(request, 'registration.html', {'registration_form': registration_form})
        user = User.objects.create_user(username=request.POST['username'], password=password, email=request.POST['email'])
        return django.http.HttpResponseRedirect('/login')
    else:
        registration_form = myApp.forms.RegistrationForm()
    return render(request, 'registration.html', {'registration_form': registration_form})

authenticate(request, username=username, password=password)で、 送られたユーザー名とパスワードが登録されているものと合致するか認証します。

認証に失敗すると、Noneが返されます。

django.contrib.authのlogin(request, user)で、

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

のuserの情報を保持したまま、他のページへ移動することができます。


re.search では正規表現を使用して文字列を取得します。

re.search(正規表現,文字列)では、第1引数に正規表現パターンを指定し、第2引数に検索させる文字列を指定します。

文字列の中に、正規表現の表現が存在するか判定します。

"\d"は、0-9のいずれか一文字にマッチする正規表現です。

アルファベットが存在するかどうかの正規表現のメタ文字がなかったので、自分で作成します。

"[a-zA-Z]"で、小文字のa-zと大文字のA-Zのいずれかを含むか判定します。"[パターン内容]"で、検索するパターンを作成できます。


Form.add_error(フィールド型のattribute, エラー)で、フィールドにエラーを追加します。

例えば、

 if len(password) < 8:
            registration_form.add_error('password', "文字数が8文字未満です。")

len(password) < 8を満たすと、フォームに入力されたpassword型のattributeに「文字列が8文字未満です」というエラーが追加されます。

なお、add_errorはattributeに複数のエラーを保持させることができます。

「文字数が8文字未満」で「数字がない」パスワードを登録すると、 f:id:mizzsugar:20180628210859p:plain

「文字数が8文字未満です。」と「数字が含まれていません」というエラーが表示されます。 f:id:mizzsugar:20180628211129p:plain


urls.pyに、ユーザー登録画面とログイン画面のurlを設定します。

urls.py

urlpatterns = [
    path("list", myApp.views.list),
    path("post_new_post", myApp.views.post_new_post),
    path('admin/', admin.site.urls),
    path("login", myApp.views.login_user),
    path("registration", myApp.views.registation_user)
]

python3 manage.py runserver myApp

でブラウザで作成した画面を動かせます。

次回は、ログアウトする方法、パスワードを変更する方法を書きます。 レイアウトの整え方も・・・!