Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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.
  • Loading branch information...
commit 493aca453aa94f160764d9a89c8043f7c9a67a78 1 parent 566e284
Senko Rašić authored May 18, 2013
11  django/forms/formsets.py
@@ -250,9 +250,9 @@ def non_form_errors(self):
250 250
         form -- i.e., from formset.clean(). Returns an empty ErrorList if there
251 251
         are none.
252 252
         """
253  
-        if self._non_form_errors is not None:
254  
-            return self._non_form_errors
255  
-        return self.error_class()
  253
+        if self._non_form_errors is None:
  254
+            self.full_clean()
  255
+        return self._non_form_errors
256 256
 
257 257
     @property
258 258
     def errors(self):
@@ -291,9 +291,12 @@ def is_valid(self):
291 291
 
292 292
     def full_clean(self):
293 293
         """
294  
-        Cleans all of self.data and populates self._errors.
  294
+        Cleans all of self.data and populates self._errors and
  295
+        self._non_form_errors.
295 296
         """
296 297
         self._errors = []
  298
+        self._non_form_errors = self.error_class()
  299
+
297 300
         if not self.is_bound: # Stop further processing.
298 301
             return
299 302
         for i in range(0, self.total_form_count()):
14  tests/forms_tests/tests/test_formsets.py
@@ -972,6 +972,20 @@ def test_increase_hard_limit(self):
972 972
         finally:
973 973
             formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM
974 974
 
  975
+    def test_non_form_errors_run_full_clean(self):
  976
+        # Regression test for #11160
  977
+        # If non_form_errors() is called without calling is_valid() first,
  978
+        # it should ensure that full_clean() is called.
  979
+        class BaseCustomFormSet(BaseFormSet):
  980
+            def clean(self):
  981
+                raise ValidationError("This is a non-form error")
  982
+
  983
+        ChoiceFormSet = formset_factory(Choice, formset=BaseCustomFormSet)
  984
+        formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
  985
+        self.assertTrue(isinstance(formset.non_form_errors(), ErrorList))
  986
+        self.assertEqual(list(formset.non_form_errors()),
  987
+            ['This is a non-form error'])
  988
+
975 989
 
976 990
 data = {
977 991
     'choices-TOTAL_FORMS': '1', # the number of forms rendered

0 notes on commit 493aca4

Please sign in to comment.
Something went wrong with that request. Please try again.