【保存版】Djangoフォームでバリデーションを実装する方法

Django

(最終更新月:2022年3月)

✔このような方へ向けて書かれた記事となります

「Djangoのバリデーションとは?役割と仕組みについて知りたい!」

「Djangoでバリデーションを実装する方法ってどんなのがあるの?」

「初心者だし、具体例が知りたい!」

✔当記事を通じてお伝えすること

  • Djangoのバリデーションとは?役割と仕組みについて
  • DjangoのValidationErrorクラスの解説
  • バリデーションの実装方法4つ
  • バリデーションの使用例「日報アプリで実装してみた」

【著者プロフィール】

profile_icon
【Python・Django歴】10年 x 【営業マン歴】11年
HP作成、社内システムの構築、コンサルティング

当ブログを通じて、下記アプリの作り方、コード等を公開、解説しています

☆日報アプリ「D-Repo」(デモ版)→こちら

※Djangoをベースに作成したアプリです

☆便利ツールアプリ「Tool Station」→こちら

※Django REST frameworkとReactで作成しているアプリです

初期費用ゼロ/月9,800円でWebデザインが学べる

デザインを習得するためには、客観的なフィードバックと改善が不可欠です。

以下の記事ではこんなWebデザインスクールをご紹介しています。

  • 初期費用ゼロで、月々9,800円のみ
  • オンラインで、教材が使い放題
  • コンテストや実務案件にチャレンジして報酬もGETできる

デザナルはトップデザイナーからレビューがもらえる、格安のWebデザインスクールです。

>>デザナルに興味がある方はこちらからどうぞ<<

詳細をまとめた記事もございますので、ぜひご覧ください。

Djangoのバリデーションとは?役割と仕組みについて

バリデーションの役割について

バリデーションとは、日本語で「検証」です。

Djangoのフォームバリデーションは、フォームに入力された値が意図したとおりになっているかを検証し、意図しない値が入力された場合にエラーを発生させることができます。

※当記事で作成している日報アプリで実装していきます。

このようにバリデーションがかかると、保存はもちろん、次のページへ進むことができません

バリデーションの仕組みについて

バリデーションの仕組みは下記の通りです。

  1. フォームの「is_validメソッド」が実行される
  2. フォームの「cleanメソッド」、「clean_フィールド名メソッド」が実行される
  3. エラーが発生した場合、ValidationErrorを投げる

つまり、意図的にエラーを発生させたい場面で、ValidationErrorを投げるよう記述すればバリデーション実装が完了します。

ただし、実装方法に移る前にValidationErrorコンストラクタについて少し詳しく見てみます。

DjangoのValidationErrorコンストラクタについて解説

ステップとしては主に2つあります。

  1. ValidationErrorのインポート
  2. raise ValidationError(引数)の記述

いくつか書き方がありますので下記の通りです。

簡易的な書き方はこちら↓

from django.core.exceptions import ValidationError

#途中のコードは割愛
raise ValidationError("ユーザー名を変更してください")

推奨されている書き方はこちら↓

from django.core.exceptions import ValidationError
from django.utils.translation import gettext as _

#途中のコードは割愛
raise ValidationError(_("ユーザー名を変更してください"), code="invalid username")
  • gettextを使用し、多言語対応にすること
  • 引数「code」に、説明を入れておくこと

エラーメッセージ内で変数を使用したい場合は、引数「params」を使います↓

ValidationError(
    _('ユーザー名を変更して下さい。(エラーコード:%(number)s'),
    params={'number': '24'},
)

以上、ValidationErrorコンストラクタの基本的な使い方を理解した上で、実装方法に移ります。

バリデーションの実装方法4つ

バリデーションを実装する方法は主に4通りです。

  1. カスタマイズしたフォームフィールドを使用する方法
  2. cleanメソッドを使う方法
  3. clean_フィールド名を使う方法
  4. validatorsを指定する方法

それぞれ見ていきます。

カスタマイズしたフォームフィールドを使用する方法

新たなフォームフィールドを作成し、フォームクラス内で使用します。

from django import forms
from django.core.validators import validate_email
from django.utils.translation import gettext as _
from django.core.exceptions import ValidationError

#こちらがカスタムフォームフィールドです
class OnlyEmailField(forms.Field):
    def to_python(self, value):
        if not value:
            return []
        return value.split(',')

    def validate(self, value):
        super().validate(value)
        for email in value:
            validate_email(email)
            if "itc.tokyo" in email:
                raise ValidationError(_("「itc.tokyo」は使用できません"), code="no-itc")

#作成したフィールドをフォームクラス内で使用します。
class 使用するフォームクラス(forms.Form):
    フィールド名 = OnlyEmailField()

「OnlyEmailField」という新たなフィールドを作成しました。

この中の「to_python」「validate」はそれぞれバリデーションの際に自動で実行されるメソッドになります。

入力した値「value」が一定の値の時に、validateメソッドでエラーを発生させることができます。

こちらの例では、下記の2ステップでバリデーションを実行しています。

  1. validate_emailで正しいEメールアドレスでない場合、エラー発生
  2. “itc.tokyo”という文字が含まれているEメールアドレスの場合、エラー発生

cleanメソッドを使う方法

from django import forms
from django.utils.translation import gettext as _
from django.core.exceptions import ValidationError

class ProfileUpdateForm(forms.Form):
    #途中のコードは割愛
    ...

    def clean(self):
        cleaned_data = super().clean()
        email = cleaned_data.get("email")

        if email:
            if "itc.tokyo" in email:
                raise ValidationError(
                    _("「itc.tokyo」は使用できません。")
                    code="no-itc"
                )

cleanメソッドは、フォームクラス内に用意されているメソッドになります。

cleanメソッドを上書きすることで新たなバリデーションを実装することが可能です。

clean_フィールド名を使う方法

from django import forms
from django.utils.translation import gettext as _
from django.core.exceptions import ValidationError

class ProfileUpdateForm(forms.Form):
    #途中のコードは割愛
    ...

    def clean_email(self):
        data = self.cleaned_data['email']
        if email:
            if "itc.tokyo" in email:
                raise ValidationError(
                    _("「itc.tokyo」は使用できません。")
                    code="no-itc"
                )
        return data

clean_フィールド名メソッドは、特定のフィールドで適用したい場合に向いています。

こちらのメソッドの場合は、最後に受け取った値をreturnすることを忘れないようにしましょう。

validatorsを指定する方法

from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

def validate_email_itc(value):
    if "itc.tokyo" in email:
        raise ValidationError(
            _("「itc.tokyo」は使用できません。")
            code="no-itc"
        )

#フィールド内で使用します。
class フォームクラス(forms.Form):
    email = forms.EmailField(validators=[validate_email_itc])

オリジナルのバリデーション関数を作成し、フィールドの引数で設定する方法です。

各フィールドで共通のバリデーションを使う時など、重宝します。

バリデーションの使用例「日報アプリで実装してみた」

今まで作成してきた日報アプリでは、ユーザー名がデフォルトでEメールアドレスになっています。

このままでは、意図せずEメールアドレスが公開されてしまうことにも繋がるので変更を促します。

今回、アカウント設定画面では下記の2つを検証します

  1. 保存される値がデフォルトのメールアドレスでないか?
  2. そもそもEメールアドレスでないか?※Eメールアドレスをユーザー名とすることを禁止しています。

【バリデーション適用後】

ユーザー名を変更せず保存すると、エラーが出るようします。

もしくは、ユーザー名にEメールアドレスを入力した場合も、エラーが出るようします。

今回の例では「clean_フィールド名」を使用し、emailフィールドに対してバリデーションを設定していきます。

accounts > forms > profile_forms.py

from django import forms
from accounts.models import Profile

class ProfileUpdateForm(forms.ModelForm):
    class Meta:
        model = Profile
        exclude = ["user"]

    def clean_username(self):
        username = self.cleaned_data.get("username")
        user_email = self.instance.user.email
        if username == user_email:
            raise forms.ValidationError("ユーザー名を変更してください")
        elif "@" in username:
            raise forms.ValidationError("ユーザー名にEメールアドレスは使用できません")
        return username

実際にエラーを発生させるための記述は下記の部分です。

if username == user_email:
    raise forms.ValidationError("ユーザー名を変更してください")
elif "@" in username:
    raise forms.ValidationError("ユーザー名にEメールアドレスは使用できません")

こちらの例ではValidationErrorコンストラクタの簡易的な方法により記述しています。

まとめ

当記事の内容をまとめます。

バリデーションの役割とは、意図しない値が入力された際にエラーを発生させることでした。

エラー発生のためには、ValidationErrorコンストラクタへ適切な値を渡すことが必要です。

バリデーションの実装方法は4つで下記の通りです。

  1. カスタムフォーフィールドの作成
  2. cleanメソッドの使用
  3. clean_フィールドメソッドの使用
  4. バリデーション関数の作成と使用

こちらをご覧頂いて、「これってなんだっけ?」というところがあれば戻って確認してみましょう。

もしくは、必要な時にまた戻ってこれるようブックマックするのもオススメです!

さて、次回の記事では、検索機能の実装方法について解説していきます。

当記事をご覧の方の中にも「そろそろウェブでアプリを公開してみたいなぁ」「どうやって公開するの?」という方もいらっしゃるのではないでしょうか?
下記の通り、別記事ではDjangoアプリの公開方法公開までの準備についての解説をしていますのでご覧ください!

「Webアプリを公開したい!」という方へ

【保存版】Apache WebサーバーでDjangoアプリを公開
Djangoが公開できる月500円~のレンタルサーバー
【初心者向け】ムームードメインで独自ドメインを取得する3ステップ
固定IPアドレスのみ単独で契約できる「インターリンク マイIP」Ubuntuコンピューターに固定IPを付与する方法

当ブログでは、日報アプリ開発を通じて、Webアプリを一から開発し公開するまでを初学者の方でもわかるようにと記事を連載しています

「Djangoでのアプリ開発を学びたい!」
「Djangoで開発したアプリをWebで公開するにはどうするの?」

という方は必見です!

【Django】チュートリアル|日報アプリの開発から公開まで
Djangoのチュートリアルをお探しですか?具体的に「手を動かして作ってみたい!」という方へ向けて、誰でもできる簡易的な日報アプリの開発を通じて、Djangoの様々な機能に触れていくシリーズとなっています。PythonでWebアプリを作りたい方、必見の記事となります!
タイトルとURLをコピーしました