formsetで外部から状態を注入したい場合。
こんな感じに書くと、何も考えずに使えて便利かもしれない。
from django.conf import settings settings.configure() import django.forms as forms from django.forms.formsets import BaseFormSet, formset_factory class ExtraArgsForm(forms.Form): def __init__(self, data=None, extra_args=None, **kwargs): super(ExtraArgsForm, self).__init__(data=data, **kwargs) if extra_args: for k, v in extra_args.items(): setattr(self, k, v) class ExtraArgsFormSet(BaseFormSet): def __init__(self, data=None, extra_args=None, **kwargs): self._extra_args = extra_args super(ExtraArgsFormSet, self).__init__(data=data, **kwargs) def _construct_form(self, i, **kwargs): """ Instantiates and returns the i-th form instance in a formset. """ defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i), "extra_args": self._extra_args } if self.is_bound: defaults['data'] = self.data defaults['files'] = self.files if self.initial: try: defaults['initial'] = self.initial[i] except IndexError: pass # Allow extra forms to be empty. if i >= self.initial_form_count(): defaults['empty_permitted'] = True defaults.update(kwargs) form = self.form(**defaults) self.add_fields(form, i) return form def extra_args_formset_factory(form, formset=ExtraArgsFormSet, extra=1, can_order=False, can_delete=False, max_num=None): return formset_factory(form, formset=formset, extra=extra, can_order=can_order, can_delete=can_delete, max_num=max_num)
使ってみる。
class SumForm(ExtraArgsForm): x = forms.IntegerField() y = forms.IntegerField() def clean(self): data = self.cleaned_data if data["x"] + data["y"] != self.sum: raise forms.ValidationError('%d + %d is not %d' % (data["x"], data["y"], self.sum)) return data SumFormSet = extra_args_formset_factory(SumForm) sum_form = SumFormSet(initial=[dict(x=10, y=90)], extra_args=dict(sum=100)) params={"form-TOTAL_FORMS" : "1", "form-INITIAL_FORMS" : "1", "form-MAX_NUM_FORMS" : None, "form-0-x" :"10", "form-0-y" :"90"} sum_form = SumFormSet(params, extra_args=dict(sum=100)) print sum_form.is_valid() print sum_form.cleaned_data sum_form = SumFormSet(params, extra_args=dict(sum=99)) print sum_form.is_valid() print sum_form.errors # True # [{'y': 90, 'x': 10}] # False # [{'__all__': [u'10 + 90 is not 99']}]