Browse Source

Fixed #32905 -- Added CSS class for non-form errors of formsets.

Ties Jan Hefting 3 years ago
parent
commit
84400d2e9d

+ 1 - 0
AUTHORS

@@ -906,6 +906,7 @@ answer newbie questions, and generally made Django that much better:
     Thomas Stromberg <tstromberg@google.com>
     Thomas Tanner <tanner@gmx.net>
     tibimicu@gmx.net
+    Ties Jan Hefting <hello@tiesjan.com>
     Tim Allen <tim@pyphilly.org>
     Tim Givois <tim.givois.mendez@gmail.com>
     Tim Graham <timograham@gmail.com>

+ 5 - 2
django/forms/formsets.py

@@ -333,7 +333,7 @@ class BaseFormSet:
         self._non_form_errors.
         """
         self._errors = []
-        self._non_form_errors = self.error_class()
+        self._non_form_errors = self.error_class(error_class='nonform')
         empty_forms_count = 0
 
         if not self.is_bound:  # Stop further processing.
@@ -380,7 +380,10 @@ class BaseFormSet:
             # Give self.clean() a chance to do cross-form validation.
             self.clean()
         except ValidationError as e:
-            self._non_form_errors = self.error_class(e.error_list)
+            self._non_form_errors = self.error_class(
+                e.error_list,
+                error_class='nonform'
+            )
 
     def clean(self):
         """

+ 4 - 0
docs/releases/4.0.txt

@@ -218,6 +218,10 @@ Forms
   error message. This allows custom error messages to use the ``%(value)s``
   placeholder.
 
+* :class:`~django.forms.formsets.BaseFormSet` now renders non-form errors with
+  an additional class of ``nonform`` to help distinguish them from
+  form-specific errors.
+
 Generic Views
 ~~~~~~~~~~~~~
 

+ 14 - 0
docs/topics/forms/formsets.txt

@@ -365,6 +365,20 @@ The formset ``clean`` method is called after all the ``Form.clean`` methods
 have been called. The errors will be found using the ``non_form_errors()``
 method on the formset.
 
+Non-form errors will be rendered with an additional class of ``nonform`` to
+help distinguish them from form-specific errors. For example,
+``{{ formset.non_form_errors }}`` would look like:
+
+.. code-block:: html+django
+
+    <ul class="errorlist nonform">
+        <li>Articles in a set must have distinct titles.</li>
+    </ul>
+
+.. versionchanged:: 4.0
+
+    The additional ``nonform`` class was added.
+
 Validating the number of forms in a formset
 ===========================================
 

+ 4 - 1
tests/admin_views/tests.py

@@ -3348,7 +3348,10 @@ class AdminViewListEditable(TestCase):
         response = self.client.post(reverse('admin:admin_views_person_changelist'), data)
         non_form_errors = response.context['cl'].formset.non_form_errors()
         self.assertIsInstance(non_form_errors, ErrorList)
-        self.assertEqual(str(non_form_errors), str(ErrorList(["Grace is not a Zombie"])))
+        self.assertEqual(
+            str(non_form_errors),
+            str(ErrorList(['Grace is not a Zombie'], error_class='nonform')),
+        )
 
     def test_list_editable_ordering(self):
         collector = Collector.objects.create(id=1, name="Frederick Clegg")

+ 14 - 0
tests/forms_tests/tests/test_formsets.py

@@ -337,6 +337,10 @@ class FormsFormsetTestCase(SimpleTestCase):
         formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
         self.assertFalse(formset.is_valid())
         self.assertEqual(formset.non_form_errors(), ['Please submit at most 1 form.'])
+        self.assertEqual(
+            str(formset.non_form_errors()),
+            '<ul class="errorlist nonform"><li>Please submit at most 1 form.</li></ul>',
+        )
 
     def test_formset_validate_min_flag(self):
         """
@@ -359,6 +363,11 @@ class FormsFormsetTestCase(SimpleTestCase):
         formset = ChoiceFormSet(data, auto_id=False, prefix='choices')
         self.assertFalse(formset.is_valid())
         self.assertEqual(formset.non_form_errors(), ['Please submit at least 3 forms.'])
+        self.assertEqual(
+            str(formset.non_form_errors()),
+            '<ul class="errorlist nonform"><li>'
+            'Please submit at least 3 forms.</li></ul>',
+        )
 
     def test_formset_validate_min_unchanged_forms(self):
         """
@@ -983,6 +992,11 @@ class FormsFormsetTestCase(SimpleTestCase):
         formset = FavoriteDrinksFormSet(data, prefix='drinks')
         self.assertFalse(formset.is_valid())
         self.assertEqual(formset.non_form_errors(), ['You may only specify a drink once.'])
+        self.assertEqual(
+            str(formset.non_form_errors()),
+            '<ul class="errorlist nonform"><li>'
+            'You may only specify a drink once.</li></ul>',
+        )
 
     def test_formset_iteration(self):
         """Formset instances are iterable."""