summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Graham <timograham@gmail.com>2017-04-28 09:32:40 -0400
committerTim Graham <timograham@gmail.com>2017-04-28 09:32:52 -0400
commite93135b067c4f2bfe423e605bdfe0786eaecaef2 (patch)
treed3d470529b88f9d70f750f5075af313a2713ee7f
parentba85929188ddcf8ba2e25c6dbeb8130a002e7676 (diff)
[1.11.x] Fixed #28130 -- Fixed formset min_num validation with initial, unchanged forms.
Regression in f5c6295797b8332134fd89e0209a18a1d1d45e0c. Backport of f04a40491764bdc9a2ebbfc03fa7be424fb3ce63 from master
-rw-r--r--django/forms/formsets.py3
-rw-r--r--docs/releases/1.11.1.txt3
-rw-r--r--tests/forms_tests/tests/test_formsets.py25
3 files changed, 30 insertions, 1 deletions
diff --git a/django/forms/formsets.py b/django/forms/formsets.py
index 7d9e84113f..3b72697c24 100644
--- a/django/forms/formsets.py
+++ b/django/forms/formsets.py
@@ -342,7 +342,8 @@ class BaseFormSet(object):
return
for i in range(0, self.total_form_count()):
form = self.forms[i]
- if not form.has_changed():
+ # Empty forms are unchanged forms beyond those with initial data.
+ if not form.has_changed() and i >= self.initial_form_count():
empty_forms_count += 1
self._errors.append(form.errors)
diff --git a/docs/releases/1.11.1.txt b/docs/releases/1.11.1.txt
index a76806c2fb..2cf7e26dfd 100644
--- a/docs/releases/1.11.1.txt
+++ b/docs/releases/1.11.1.txt
@@ -58,3 +58,6 @@ Bugfixes
* Fixed crash when overriding the template of
``django.views.static.directory_index()`` (:ticket:`28122`).
+
+* Fixed a regression in formset ``min_num`` validation with unchanged forms
+ that have initial data (:ticket:`28130`).
diff --git a/tests/forms_tests/tests/test_formsets.py b/tests/forms_tests/tests/test_formsets.py
index 29f0befc18..1c431e5e22 100644
--- a/tests/forms_tests/tests/test_formsets.py
+++ b/tests/forms_tests/tests/test_formsets.py
@@ -405,6 +405,31 @@ class FormsFormsetTestCase(SimpleTestCase):
self.assertFalse(formset.is_valid())
self.assertEqual(formset.non_form_errors(), ['Please submit 3 or more forms.'])
+ def test_formset_validate_min_unchanged_forms(self):
+ """
+ min_num validation doesn't consider unchanged forms with initial data
+ as "empty".
+ """
+ initial = [
+ {'choice': 'Zero', 'votes': 0},
+ {'choice': 'One', 'votes': 0},
+ ]
+ data = {
+ 'choices-TOTAL_FORMS': '2',
+ 'choices-INITIAL_FORMS': '2',
+ 'choices-MIN_NUM_FORMS': '0',
+ 'choices-MAX_NUM_FORMS': '2',
+ 'choices-0-choice': 'Zero',
+ 'choices-0-votes': '0',
+ 'choices-1-choice': 'One',
+ 'choices-1-votes': '1', # changed from initial
+ }
+ ChoiceFormSet = formset_factory(Choice, min_num=2, validate_min=True)
+ formset = ChoiceFormSet(data, auto_id=False, prefix='choices', initial=initial)
+ self.assertFalse(formset.forms[0].has_changed())
+ self.assertTrue(formset.forms[1].has_changed())
+ self.assertTrue(formset.is_valid())
+
def test_formset_validate_min_excludes_empty_forms(self):
data = {
'choices-TOTAL_FORMS': '2',