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

※本サイトにはプロモーション・広告が含まれています。

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

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

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

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

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

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

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

✔YouTube解説動画

当記事の内容は動画を見ながら進めると、約15分程度で完了します。

動画ならではの情報も解説しているので、記事と一緒にご覧ください。

動画の概要欄には、単元ごとのコードを紹介しているgithubページも載せています。

筆者プロフィール

筆者プロフィールアイコン

【現職】プロダクトマネージャー

【副業】ブログ(月間17万PV)/YouTube/Web・アプリ制作

「プログラミング × ライティング × 営業」の経験を活かし、30後半からのIT系職へシフト。当サイトでは、実際に手を動かせるWebアプリの開発を通じて、プログラミングはもちろん、IT職に必要な情報を提供していきます。

【当ブログで紹介しているサイト】

当サイトチュートリアルで作成したデモ版日報アプリ

Django × Reactで開発したツール系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.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. バリデーション関数の作成と使用

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

さて、次回のチュートリアル記事では、日報アプリに下書き・公開機能をつけていく方法やその実装例をご覧いただきます。

タイトルとURLをコピーしました