diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index a0a38f3..3893cc5 100644
a
|
b
|
class BaseFormSet(object):
|
267 | 267 | |
268 | 268 | def is_valid(self): |
269 | 269 | """ |
270 | | Returns True if form.errors is empty for every form in self.forms. |
| 270 | Returns True if every form in self.forms is valid. |
271 | 271 | """ |
272 | 272 | if not self.is_bound: |
273 | 273 | return False |
… |
… |
class BaseFormSet(object):
|
282 | 282 | # This form is going to be deleted so any of its errors |
283 | 283 | # should not cause the entire formset to be invalid. |
284 | 284 | continue |
285 | | if bool(self.errors[i]): |
286 | | forms_valid = False |
| 285 | forms_valid &= form.is_valid() |
287 | 286 | return forms_valid and not bool(self.non_form_errors()) |
288 | 287 | |
289 | 288 | def full_clean(self): |
diff --git a/tests/regressiontests/forms/tests/formsets.py b/tests/regressiontests/forms/tests/formsets.py
index b3ceee5..bf893c4 100644
a
|
b
|
class FormsFormsetTestCase(TestCase):
|
856 | 856 | formset = FavoriteDrinksFormSet(error_class=CustomErrorList) |
857 | 857 | self.assertEqual(formset.forms[0].error_class, CustomErrorList) |
858 | 858 | |
| 859 | def test_formset_calls_forms_is_valid(self): |
| 860 | # Regression tests for #18574 -- make sure formsets call |
| 861 | # is_valid() on each form. |
| 862 | |
| 863 | class AnotherChoice(Choice): |
| 864 | def is_valid(self): |
| 865 | self.is_valid_called = True |
| 866 | return super(AnotherChoice, self).is_valid() |
| 867 | |
| 868 | AnotherChoiceFormSet = formset_factory(AnotherChoice) |
| 869 | data = { |
| 870 | 'choices-TOTAL_FORMS': '1', # number of forms rendered |
| 871 | 'choices-INITIAL_FORMS': '0', # number of forms with initial data |
| 872 | 'choices-MAX_NUM_FORMS': '0', # max number of forms |
| 873 | 'choices-0-choice': 'Calexico', |
| 874 | 'choices-0-votes': '100', |
| 875 | } |
| 876 | formset = AnotherChoiceFormSet(data, auto_id=False, prefix='choices') |
| 877 | self.assertTrue(formset.is_valid()) |
| 878 | self.assertTrue(all([form.is_valid_called for form in formset.forms])) |
| 879 | |
859 | 880 | |
860 | 881 | data = { |
861 | 882 | 'choices-TOTAL_FORMS': '1', # the number of forms rendered |