Commit 493aca45 authored by Senko Rasic's avatar Senko Rasic
Browse files

Fixed #11160 - Ensure full_clean is called from non_form_errors

Updated FormSet.non_form_errors() to ensure full_clean() has
been called before returning the errors.
parent 566e284c
Loading
Loading
Loading
Loading
+7 −4
Original line number Diff line number Diff line
@@ -250,9 +250,9 @@ class BaseFormSet(object):
        form -- i.e., from formset.clean(). Returns an empty ErrorList if there
        are none.
        """
        if self._non_form_errors is not None:
        if self._non_form_errors is None:
            self.full_clean()
        return self._non_form_errors
        return self.error_class()

    @property
    def errors(self):
@@ -291,9 +291,12 @@ class BaseFormSet(object):

    def full_clean(self):
        """
        Cleans all of self.data and populates self._errors.
        Cleans all of self.data and populates self._errors and
        self._non_form_errors.
        """
        self._errors = []
        self._non_form_errors = self.error_class()

        if not self.is_bound: # Stop further processing.
            return
        for i in range(0, self.total_form_count()):
+14 −0
Original line number Diff line number Diff line
@@ -972,6 +972,20 @@ class FormsFormsetTestCase(TestCase):
        finally:
            formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM

    def test_non_form_errors_run_full_clean(self):
        # Regression test for #11160
        # If non_form_errors() is called without calling is_valid() first,
        # it should ensure that full_clean() is called.
        class BaseCustomFormSet(BaseFormSet):
            def clean(self):
                raise ValidationError("This is a non-form error")

        ChoiceFormSet = formset_factory(Choice, formset=BaseCustomFormSet)
        formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
        self.assertTrue(isinstance(formset.non_form_errors(), ErrorList))
        self.assertEqual(list(formset.non_form_errors()),
            ['This is a non-form error'])


data = {
    'choices-TOTAL_FORMS': '1', # the number of forms rendered