unique togetherを指定したモデルのエラーメッセージのカスタマイズ

※Django1.6だと「validate_uniqueメソッドをオーバーライド」でエラーが発生するみたいなので、ご注意ください。

Djangoにはdjango.forms.ModelFormという、DBのモデルに対応したフォームを作成する機能があります。この記事では、フォームの元となるモデルにunique_togetherを指定した場合の、バリデーションエラーのメッセージをカスタマイズする方法を3つ紹介しています。そのカスタマイズ方法の柔軟性ですが、3番目が一番が高く、次に2番目・1番目と続きます。

目次

  1. デフォルトのエラーメッセージ
  2. verbose_nameを定義
  3. unique_error_messageメソッドをオーバーライド
  4. validate_uniqueメソッドをオーバーライド

デフォルトのエラーメッセージ

まずは特に設定をしない場合です。unique_togetherのバリデーションエラーのメッセージは、デフォルトでは「(フィールド名)と(フィールド名)...を持ったUnique Togetherが既に存在します。」という形式で表示されます。このままでも意味は通じるので、社内システムなどにはいいかもしれません。ただ、ユーザーが見える場所にこのメッセージを表示するのはちょっと厳しいと思います。

以下がコードになります。

form.html

{% load markup %}
<html>
  <head>
    <title>Form</title>
    <style>
      body { 
        margin: 0;
        padding: 0;
        font-size: 15px;
      }
      form {
        width: 280px;
        margin: 40px 0 0 40px;
        padding: 18px;
        background-color: #f0f0f0;
        border: 1px solid #ccc;
        box-shadow: 1px 1px 3px #999;
      }
      p {
        margin: 0;
        padding: 0;
      }
      button {
        border: 1px outset #f0f0f0;
        cursor: pointer;
        background-color: #fff;
        width: 120px;
        height: 28px;
        font-size: 16px;
      }
      .field_wrapper {
        margin-bottom: 16px;
      }
      .field_wrapper p {
        margin-bottom: 2px;
      }
      .field_wrapper ul.errorlist {
        margin: 3px 0 3px 15px;
        padding: 0;
        color: #f33;
      }
      .field_wrapper input {
        font-size: 16px;
        width: 100%;
      }
      .button_wrapper {
        margin-top: 20px;
        text-align: right;
      }
    </style>
  </head>
  <body>
    <form method="post" action="{% url myapp.views.add_commit %}">
      {% if form.non_field_errors %}
      <div class="field_wrapper">
        {{ form.non_field_errors }}
      </div>
      {% endif %}
      <div class="field_wrapper">
        <p>名前: </p>
        {{ form.name.errors }}
        {{ form.name }}
      </div>
      <div class="field_wrapper">
        <p>スラッグ: </p>
        {{ form.slug.errors }}
        {{ form.slug }}
      </div>
      <div class="button_wrapper">
        <button type="submit">新規登録</button>
      </div>
    </form>
  </body>
</html>

models.py

# -*- coding: utf-8 -*-

from django.db import models


class UniqueTogether(models.Model):
    class Meta:
        unique_together = ('name', 'slug')

    name = models.CharField(max_length=128)
    slug = models.SlugField()

forms.py

# -*- coding: utf-8 -*-

from django import forms
from myapp.models import UniqueTogether


class UniqueTogetherForm(forms.ModelForm):
    class Meta:
        model = UniqueTogether
        fields = ('name', 'slug')

views.py

# -*- coding: utf-8 -*-

from django.shortcuts import render_to_response, redirect
from django.core.urlresolvers import reverse
from django.views.decorators.csrf import csrf_exempt
from myapp.forms import UniqueTogetherForm

def add_view(request):
    form = UniqueTogetherForm()
    return render_to_response('form.html', dict(form=form))

@csrf_exempt
def add_commit(request):
    form = UniqueTogetherForm(request.POST)
    if not form.is_valid():
        return render_to_response('form.html', dict(form=form))
    form.save()
    return redirect(reverse('myapp.views.add_view'))

↑ 目次に戻る

verbose_nameを定義

unique_togetherの、エラーメッセージカスタマイズのカスタマイズ法の1つ目はmodels.pyに「verbose_name」を定義する方法です。これを定義すると、先ほどのエラーメッセージの「Name」・「Slug」・「Unique together」といった文言が、定義した文字列に変更されます。

上の画像で、「Name」などが「verbose_name」に置き換わっているのがわかるかと思います。

verbose_nameを定義したmodels.py

# -*- coding: utf-8 -*-

from django.db import models


class UniqueTogether(models.Model):
    class Meta:
        unique_together = ('name', 'slug')
        verbose_name = u'モデル'

    name = models.CharField(max_length=128, verbose_name=u'名前')
    slug = models.SlugField(verbose_name=u'スラッグ')

↑ 目次に戻る

unique_error_messageメソッドをオーバーライド

unique togetherのエラーメッセージ変更の2つめのやり方です。次のやり方は、django.db.models.Modelの「unique_error_message」メソッドをオーバーライドする方法です。この方法だと、「verbose_name」とは違って自由に文言を変更することができます。この例では「forms.py」を修正して、同メソッドをオーバーライドしています。

forms.py

# -*- coding: utf-8 -*-

from django import forms
from myapp.models import UniqueTogether


class UniqueTogetherForm(forms.ModelForm):
    class Meta:
        model = UniqueTogether
        fields = ('name', 'slug')

    def __init__(self, *args, **kwargs):
        super(UniqueTogetherForm, self).__init__(*args, **kwargs)
        self.instance.unique_error_message = lambda m, u: u'Unique Togetherのエラーメッセージを変更しました。'

↑ 目次に戻る

validate_uniqueメソッドをオーバーライド

最後は、django.forms.ModelFormに定義されている、「validate_unique」メソッドをオーバーライドする方法です。この場合、「self.cleaned_data」から入力値にアクセスできるため、今回紹介した3つの方法の中では一番柔軟にエラーメッセージをカスタマイズすることができます。

forms.py

# -*- coding: utf-8 -*-

from django import forms
from myapp.models import UniqueTogether


class UniqueTogetherForm(forms.ModelForm):
    class Meta:
        model = UniqueTogether
        fields = ('name', 'slug')

    def validate_unique(self):
        exclude = self._get_validation_exclusions()
        try:
            self.instance.validate_unique(exclude=exclude)
        except forms.ValidationError, e:
            name = self.cleaned_data['name']
            slug = self.cleaned_data['slug']
            self._update_errors(dict(__all__=[u'validate_uniqueをオーバーライドして、エラーメッセージを変更しました。name: %(name)s, slug: %(slug)s' % locals()]))

↑ 目次に戻る

この記事が役に立った場合、シェアしていただけると励みになります!!