djangoで0からログイン機能を実装するパート2-formを使用した高度なコード-

前回の続きになります。

今回は

  • formを利用
  • バリデーションチェックをいれる

を使用することにより、セキュリティ面の向上に繋がり本格的なログインフォームの実装となります。

環境

環境

・Python 3.8

・Django 2.2

ログイン表示部分

ログインするための画面になります。

前回と違うのは{{ form }}で囲まれたdjangoテンプレートを使用します。

{{ user }}
<form action="" method="POST">
    {% csrf_token %}
    <div>{{ form.non_field_errors }}</div>
    <div>{{ form.username }}{{ form.username.errors }}</div>
    <div>{{ form.password }}{{ form.password.errors }}</div>
    <button type="submit">login</button>
</form>

一番上の{{ user }}は前回同様のログイン中のユーザーになります。

djangoテンプレートを利用しているのでシンプルに見えますが、これからform箇所はバリデーションを書いたりと高度な記述をしていきます。

ちなみに、{{ form.username.errors }}は、usernameを入力する箇所へのエラーが存在するときのエラーを発生させるテンプレートになります。

{{ form.username.errors }}は、passwordを入力する箇所へのエラーが存在するときのエラーを発生させるテンプレートになります。

{{ form.non_field_errors }}は、usernameとpasswordで互いに依存するフィールドをクリーニングして検証し、エラーがある場合はエラーを発生させるテンプレートになります。

viewsの基幹箇所

前回よりもコードの量も増えています。

views.py

from django.views.decorators.http import require_http_methods
from .forms import LoginForm
from django.contrib.auth import authenticate, login

@require_http_methods(['GET', 'POST'])
def inquiry_login(request):
    if request.method != 'POST':
        if str(request.user) != 'AnonymousUser':
            form = ''
        else:
            form = LoginForm()
    else:
        form = LoginForm(request.POST)
        if form.is_valid():
            username = form.clean_data['username']
            password = form.clean_data['password']
            user = authenticate(username=username, password=password)
            if user is not None:
                login(request, user)
                return HttpResponseRedirect(reverse('inquiry_apps:inquiry_list'))
            else:
                pass
    context = {
        'form': form,
    }
    return render(request, 'inquiry_apps/login.html', context)
  • 1行目のfrom django.views.decorators.http import require_http_methodsで、@require_http_methods([‘GET’, ‘POST’])のmethodsを指定します。
  • 7行目のif request.method != ‘POST’:は、’POST’メソッドではない、つまり、’GET’メソッド時(リダイレクト時の最初の画面)を表します。
  • 8行目のif str(request.user) != ‘AnonymousUser’:は、ログイン中の場合の意味とし、誰かがログインしている時はログインフォームを隠すform=”、つまり空欄という意味になります。
  • 12行目のelse:は、htmlでbuttonをクリックされた時の処理になります。
  • 14行目のif form.is_valid():はバリデーションのお作法なもので、form13行目で値を受け取ったらすぐにform.is_valid()と書いてバリデーションチェックに移ります。
  • 15行目、16行目でバリデーションチェックになります。この処理これから下にかくform側での処理です。

入力formとバリデーションチェック

formsは

  1. ユーザーの入力データの保持
  2. 入力データのバリデーション(妥当性チェック)を行い、妥当性検証済みのデータやエラーメッセージを保持する役割があります。

forms.py

from django import forms
from django.core.exceptions import ValidationError

from django.contrib.auth import authenticate

class LoginForm(forms.Form):
    username = forms.CharField(required=True,
                                max_length=30,
                                widget=forms.TextInput(
                                    attrs={
                                        'placeholder': 'User name'
                                    }
                                ),)
    
    password = forms.CharField(required=True,
                                max_length=255,
                                widget=forms.PasswordInput(
                                    attrs={
                                        'placeholder': 'Password'
                                    }
                                ))


    def clean(self):
        cleaned_data = super(LoginForm, self).clean()
        if 'username' and 'password' in cleaned_data:
            auth_result = authenticate(username=cleaned_data['username'], password=cleaned_data['password'])
            if not auth_result:
                raise ValidationError('Wrong username or password')
        return cleaned_data

    def clean_username(self):
        username = self.cleaned_data['username']
        return username

    def clean_password(self):
        password = self.cleaned_data['password']
        return password
  • 2行目のfrom django.core.exceptions import ValidationErrorはその名の通り、バリデーション(妥当性チェック)に引っかかった時のエラーを起こすためのValidationErrorメソッドを呼び出す処理になります。
  • 7行目のrequire=Trueは、入力必須を意味します。
  • 8行目のmax_length=255はこの入力フォームで255文字以内の入力を意味します。
  • 9行目のwidgetに関して、formsからPasswordInputメソッドを呼び出し、入力時に値が黒丸表示で隠れるような仕様になっています。また引数attrsの辞書型オブジェクトのキーに’placeholder’、バリューに、’User name’を記述することで、入力フォーム時の背景にうっすらとPasswordが表示され、ユーザーがどこに入力すれば良いのかの認知性をあげます。
  • 24行目のcleanはnameとpasswordの互いに依存するフィールドをクリーニングして検証します。ここで双方がuserに登録された名前とパスワードが一致するのか否かを検証し、そうでない場合は29行目の処理へと移り、raise ValidationErrorでエラー表示を発生させます。
  • 33行目はusernameの個別のバリデーション処理になります。
  • 37行目はpasswordの個別のバリデーション処理になります。

実際のログイン画面へ

urls.pyは前回同様のままです。

ここまでできれば下記のような画面になっているはずです。

例えばこのまま何も入力しないで、loginボタンをクリックしてみます。

このようにバリデーションが働いてフィールドに入力を求められます。

次に、でたらめな値を入れてloginボタンをクリックしてみます。

forms.pyで記述した、ユーザー名またはパスワードが違いますのバリデーションエラーが発生します。

きちんとした値を入力してみます。

このようにパスワード箇所は黒丸でhideされています。

前回記事で作成したユーザーとパスワードが適合している場合はログインが可能となります。


スクールを利用して本格的に学ぶ

いかがでしたでしょうか?

今回10人中9人が挫折すると言われるプログラミングを、半年間もの間頑張れ、結果、今はPythonエンジニアとして働く事ができているのも、プログラミングスクールを利用して自ら目標を設定して講師の言う通りにひたすら打ち込んだまでです。

挫折率が高いプログラミングこそお金を払ってメンターを付けて、道を見失わないように環境を構築する必要があるのではないでしょうか。

結局一人だとどうしてもだらけてしまいます。

これはダイエットで自分一人では痩せられないけど、トレーナーを付けて否が応でもせざるを得ない環境を作ると一緒ですね。

ヒロヤンもプログラミング勉強開始直後はあれこれ悩みましたが、悩むよりも手っ取り早くスクールに登録した方が最短ルートで勉強できるのではないかと考えました。

無料カウンセリングで、あなたの悩みを相談してみてはいかがでしょうか?

テックキャンプで無料相談を受ける

上記リンク先から無料相談ができます。

コメントを残す

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です