Web屋さんのアレ

Python大好きなWeb屋のおじさんがぺろぺろ何かを書いてくよ。

【Python】Modelクラスでclean_[field_name]メソッドを使う【Django】

Djangoのforms.Formクラスにあるアレです。
Modelにも実装してくれればいいのに。。

Modelにもカスタムバリデーション用のcleanメソッドがありますけども、あすこでValidationErrorを投げるとどんな設定してもNON_FIELD_ERRORSのエラーになってしまいます。
こりゃー使いづらいぜーという事なのでFormクラスと似たような事が出来るようにMixinを使って実装をしてみました。
と言ってもDjangoのソースパクって数行追加するだけですけども。

#-*-coding=utf8-*-

from django.core.exceptions import ValidationError

class CleanFieldModelMixin(object):
"""clean_[field_name]メソッドが使えるようになります。"""

def clean_fields(self, exclude=None):
if exclude is None: exclude = []

errors = {}
for f in self._meta.fields:
if f.name in exclude: continue

raw_value = getattr(self, f.attname)
if f.blank and raw_value in validators.EMPTY_VALUES: continue

try:
setattr(self, f.attname, f.clean(raw_value, self))
if hasattr(self, 'clean_%s' % f.name):
value = getattr(self, 'clean_%s' % f.name)()
setattr(self, f.attname, value)
except ValidationError, e:
errors[f.name] = e.messages

if errors:
raise ValidationError(errors)

んで、実際の使い方はこんな感じ

#-*-coding=utf8-*-

from django.db import models
from django.core.exceptions import ValidationError
from utils.models import CleanFieldModelMixin # 適当にして下さいな。

# MixinクラスはModelクラスより先に書いてくださいね!
class User(CleanFieldModelMixin, models.Model):
name = models.CharField('name', max_length=60)

def clean_name(self):
count = User.objects.filter(name=self.name).count()
if count > 0:
raise ValidationError('%s is already exists.' % self.name)

これで動く。
多分動く。。