[Django] FormのValidationの方法と設定箇所まとめ。ValidationErrorの動作確認方法やFormClass,ModelClassでの検証方法

目次

Validationとは?

  • FORMからPOSTされたデータが正しい形式か検証(Validate)する機能である。
  • 例えばメールアドレスのデータがxxxxxx@xxxx.xxの形式かチェックすることを指す
  • Djangoには様々なValidation機能が存在する。
  • もちろんカスタマイズして利用することも可能

ValidationErrorについて

  • ValidationErrorはエラー発生時に実行されるクラス
  • FORMのValidationはいくつかのステップで行われている。
  • ステップはフォームとフィールドの検証を参照
  • ValidationErrorを発生させることで、FORMはValidation失敗を検知してエラーを返す。

Validationの動作検証方法

Validationの検証のためにFORM、Templateなどを全て用意する必要はない。manage.py shellを使用すれば良い。
なお、今回使用するModelとFormは以下とする。

models.py

from django.db import models

class Post(models.Model):
    id = models.AutoField(primary_key=True,
                          db_column='id')
    title = models.CharField(max_length=255,
                             null=False,
                             blank=False,
                             db_column='title')

forms.py

from django import forms
from .models import Post

class CmsCreateViewForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = (
            'title',
            'content',
        )

ここからは検証方法。
まずはshellを起動。

python manage.py shell

次にformsのインポートして、formsのクラスをインスタンス化する。
ここのdataの値を変えることでValidationチェックが可能

>>> from app.forms import CmsCreateViewForm
>>> data = {'title': 'shell', 'content': 'shell'}
>>> f = CmsCreateViewForm(data)

is_valid()でValidationを実行。Falseなので失敗していることがわかる。

>>> f.is_valid()
False

erorrsやnon_field_errorsで何のエラーか分かる。

>>> f.errors
{'__all__': ['Title length is short.'], 'title': ['Title length is short.']}
>>> f.non_field_errors
<bound method BaseForm.non_field_errors of <CmsCreateViewForm bound=True, valid=False, fields=(title;content;image)>>

エラーについて詳しくは以下の記事を参照。

[Django] Formのエラーをtemplateに表示する方法のまとめ。errorsとnon_filed_errorsの違いについて

FormClassでValidation

ModelClassやFormClassは上記のものを一部流用する。

Formで発生させる箇所は大きく分けて2つ。

  • FieldでValidatorを起動
  • clean_{filed}()とclean()メソッドでエラーを設定

まずはFieldにValidatorを設定する場合である。
Validation用の関数を用意して設定する。validatorsにはリストで関数を指定するため、複数のValidationも設定可能。

from django import forms
from .models import Post

def check_title_length(value):
    if len(value) < 10:
        raise ValidationError('Title length is short.')

class CmsCreateViewForm(forms.Form):
    title = forms.CharField(validators=[check_title_length])

clean{filed}()とclean()メソッドは以下のように書く。
clean
{filed}()は各Fieldごとに設定可能で、errorsとnon_field_errorsのどちらのエラーに格納させるか設定可能。
cleanはField間の整合性などを取る時に使用し、エラーは必ずnon_field_errorsに入る点に注意。

from django import forms
from .models import Post

class CmsCreateViewForm(forms.ModelForm):
    class Meta:
        model = Post
        fields = (
            'title',
            'content',
        )

    def clean_title(self):
        title = self.cleaned_data.get('title')
        if len(title) <= 10:
            self.add_error(None, 'Title length is short.')
        return title

    def clean(self):
        title = self.cleaned_data.get('title')
        content = self.cleaned_data.get('content')
        if content.find(title):
            raise forms.ValidationError('Title and content do not match.')
        return self.cleaned_data

ModelClassでValidation

ModelClassやFormClassは上記のものを一部流用する。

ModelFormを使用する時にModelClassにValidationを指定することも可能。

from django.db import models
from django.core.exceptions import ValidationError
from django.utils import timezone

def check_title_length(value):
    if len(value) < 10:
        raise ValidationError('Title length is short.')

class Post(models.Model):
    id = models.AutoField(primary_key=True,
                          db_column='id')
    title = models.CharField(max_length=255,
                             null=False,
                             blank=False,
                             validators=[check_title_length],
                             db_column='title')

どこのValidationを設定すべきか?

  • Projectごとで決まると思っている。
  • 個人的な見解としてはDjangoがValidationのStepに合わせて設定することが好ましいと考えている。
  • 例えばModelFormを使用している場合はmodelクラスに設定する。
  • ただModelには定義だけ書く場合にはclean_xx関数に書こうと考えている。
目次
閉じる