どうやるのかなと思って調べたときのメモ
例えば複数のブックマークを一括で入力できる画面を想定して、こんなFormとFormSetがある場合
from django.forms.formsets import formset_factory from django import forms class BookmarkForm(forms.Form): title = forms.CharField(max_length=100) url = forms.CharField(max_length=100) BookmarkFormSet = formset_factory(BookmarkForm, extra=1, max_num=100)
同じurlのブックマークが入力された場合にエラーにする、というのは各FormのバリデーションではできないのでFormSetの仕事になる。
FormSetにバリデーションの処理をさせるにはBaseFormSetを継承したクラスにcleanメソッドを実装し、formset_factoryの引数として渡す。
from django.forms.formsets import formset_factory from django import forms class BookmarkForm(forms.Form): title = forms.CharField(max_length=100) url = forms.CharField(max_length=100) class BaseBookmarkFormSet(BaseFormSet): def clean(self): url_list = [form['url'].value() for form in self.forms] if len(url_list) > len(set(url_list)): raise forms.ValidationError, u'duplicate url' BookmarkFormSet = formset_factory(BookmarkForm, formset=BaseBookmarkFormSet, extra=1, max_num=100)
Formsetのcleanメソッドは、各Formのバリデーションが全て実行されたあとに実行される。
エラーはnon_form_errorsメソッドで取得できる。
>>> data = {'form-TOTAL_FORMS': u'2', 'form-INITIAL_FORMS': u'2', 'form-0-title': '', 'form-0-url': 'http://www.yahoo.co.jp', 'form-1-title': u'Yahoo! Japan', 'form-1-url': 'http://www.yahoo.co.jp', } >>> fs = BookmarkFormSet(data) >>> fs.is_valid() False >>> fs.errors [{'title': [u'This field is required.']}, {}] >>> fs.non_form_errors() [u'duplicate url']