[1.5.x] Fixed #18574 -- Make BaseFormSet.is_valid call its underlying forms' is_valid

Thanks Simon Charette for the report and the initial patch.
Backport of 66dfcc10b from master.
This commit is contained in:
Andreas Hug 2012-12-06 20:00:56 +01:00 committed by Claude Paroz
parent e9301ae451
commit 67bddc0b7b
2 changed files with 23 additions and 3 deletions

View File

@ -267,7 +267,7 @@ class BaseFormSet(object):
def is_valid(self):
"""
Returns True if form.errors is empty for every form in self.forms.
Returns True if every form in self.forms is valid.
"""
if not self.is_bound:
return False
@ -282,8 +282,7 @@ class BaseFormSet(object):
# This form is going to be deleted so any of its errors
# should not cause the entire formset to be invalid.
continue
if bool(self.errors[i]):
forms_valid = False
forms_valid &= form.is_valid()
return forms_valid and not bool(self.non_form_errors())
def full_clean(self):

View File

@ -856,6 +856,27 @@ class FormsFormsetTestCase(TestCase):
formset = FavoriteDrinksFormSet(error_class=CustomErrorList)
self.assertEqual(formset.forms[0].error_class, CustomErrorList)
def test_formset_calls_forms_is_valid(self):
# Regression tests for #18574 -- make sure formsets call
# is_valid() on each form.
class AnotherChoice(Choice):
def is_valid(self):
self.is_valid_called = True
return super(AnotherChoice, self).is_valid()
AnotherChoiceFormSet = formset_factory(AnotherChoice)
data = {
'choices-TOTAL_FORMS': '1', # number of forms rendered
'choices-INITIAL_FORMS': '0', # number of forms with initial data
'choices-MAX_NUM_FORMS': '0', # max number of forms
'choices-0-choice': 'Calexico',
'choices-0-votes': '100',
}
formset = AnotherChoiceFormSet(data, auto_id=False, prefix='choices')
self.assertTrue(formset.is_valid())
self.assertTrue(all([form.is_valid_called for form in formset.forms]))
data = {
'choices-TOTAL_FORMS': '1', # the number of forms rendered