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

目次

Formからエラーを取得する仕組み

  • DjangoのFormの値チェック(Validation)は、値のクリーニング(clean)させる時に行われる。要はPOSTされたデータを受け取り、使える形に整形中にValidationが行われる。
  • またFormのValidationは複数のステップ分かれる。またこれらはカスタムやオーバーライドすることが可能
  • FormクラスやModelクラスのValidator、Formクラスのclean_xxxやcleanメソッドなどでValidationを行うということである。

要はややこしい仕様がたくさんあるということ。

errorsとnon_filed_errorsの違いについて

  • 一般的にはValidation違反となったらValidationErrorクラスに投げられる。
  • その際に違反発生時の指定方法によって、特定Fieldのエラーと紐付けられていないエラーに分けられる。
  • 特定Fieldのエラーがerrors、紐付けられていないエラーがnon_filed_errorsの2つに分けられる。
  • clean_xxxやadd_error()を使用して、どのFieldのエラーか任意に設定できる。
  • もちろんadd_error(None, ‘Erorr’)は特定エラーを指定しないことも可能。

errorsとnon_field_errorsへのセット方法

今回はModelForm+CreateViewを利用したパターンで説明する。
以下のサンプルModelを利用する。

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')
    content = models.TextField(null=False,
                               blank=True,
                               db_column='content')

errorsに格納されるパターン
add_errorで’title’を指定しているため、Titleのフィールドのエラーとなる。
また、clean_titleと指定すると、raise forms.ValidationErrorでもtitleのエラーに格納させる。

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('title', 'Title length is short.') ★
            raise forms.ValidationError('Title length is short.') ★
        return title

もちろんValidatorの関数を用意したModelのValidatorでも該当Fieldのエラーとなる。

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

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')
    content = models.TextField(null=False,
                               blank=True,
                               db_column='content')

non_filed_errorに格納されるパターン。
明示的にadd_errorでNoneを指定する必要ある。

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

templateへの表示方法

errorsの場合は、errorlistのulタグにliタグが作成させる。
以下のように書く。

{{ form.title.errors }}

ただし展開されると表示は
<ul class="errorlist">
    <li>Error Message1</li>
    <li>Error Message2</li>
</ul>
となる

エラーメッセージだけにしたい場合は以下のよう書く。

<ul>
    {% for error in form.title.errors %}
    <li>
        {{ error }}
    </li>
    {% endfor %}
</ul>

ちなみに
{{ form.title.errors.0 }}
{{ form.title.errors.1 }}
とするとエラーメッセージだけ取得できる。

non_field_errorの場合は以下のように書く。
liタグとして出力されないのがポイントです

<ul>
    {% for error in form.non_field_errors %}
    <li>{{ error }}</li>
    {% endfor %}
</ul>
よかったらシェアしてね!
  • URLをコピーしました!
目次