Django:清理和验证相互依赖的FORMS

Dol*_*lph 6 django validation django-forms

django文档涵盖了相互依赖的清理和验证FIELDS,但我找不到任何涵盖彼此依赖的形式的内容.

我有一个HTML表单,其中包含标准的django表单和django表单集.对表单集中每个表单的正确验证完全是基于主表单中的值的条件(例如,检查主表单上的框,并且突然需要在表单集中的每个表单上的特定字段).

我的直觉是"简单地"将整个主窗体传递给formset验证调用,如下所示:

def my_view(request):
    MyFormSet = formset_factory(MyForm, extra=2, can_order=True)

    if request.method == 'POST':
        form = MainForm(request.POST)
        formset = MyFormSet(request.POST)

        if form.is_valid() and formset.is_valid(form): # <-- ?!?!
            # The formset is now validated based on the form
Run Code Online (Sandbox Code Playgroud)

但是,为了完成这项工作,我相信我必须覆盖formset is_valid()以及底层的表单is_valid()clean()方法.所以,它很快就变得非常混乱.

有一个更好的方法吗?

Ted*_*Ted 8

我曾经调查过做过这样的事情,本教程http://yergler.net/blog/2009/09/27/nested-formsets-with-django/非常有帮助.

另一种方法是:

def my_view(request):
MyFormSet = formset_factory(MyForm, extra=2, can_order=True)

if request.method == 'POST':
    form = MainForm(request.POST)
    formset = MyFormSet(request.POST, other_form = form)

    if form.is_valid() and formset.is_valid(): # <-- ?!?!
        # The formset is now validated based on the form
Run Code Online (Sandbox Code Playgroud)

然后

class MyFormSet(...):

   def __init__(self, *args, **kwargs):
       if kwargs.has_key('other_form'):
           self.myformforlater = kwargs.pop('other_form')
       Super(MyFormSet, self).__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这样您只需覆盖init方法,并且可以从任何验证步骤访问外部表单.


Dol*_*lph 6

这是我最终得到的代码,使用Ted的答案(django 1.3):

class BaseMyFormSet(BaseFormSet):
    main_form = None

    def __init__(self, *args, **kwargs):
        # Save the main form until validation
        if kwargs.has_key('main_form'):
            self.main_form = kwargs.pop('main_form')

        super(BaseMyFormSet, self).__init__(*args, **kwargs)

    def clean(self):
        if any(self.errors):
            # Don't bother validating the formset unless each 
            # form is valid on its own
            return

        checkbox = self.main_form.cleaned_data['my_checkbox']

        if checkbox:
            for form in self.forms:
                # Do some extra validation


def my_view(request):
    MyFormSet = formset_factory(MyForm, extra=2, can_order=True,
        formset=BaseMyFormSet)

    if request.method == 'POST':
        form = MainForm(request.POST)
        formset = MyFormSet(request.POST, main_form=form)

        if form.is_valid() and formset.is_valid():
            # The formset is now validated based on the form
Run Code Online (Sandbox Code Playgroud)