Loading django/forms/formsets.py +4 −4 Original line number Diff line number Diff line Loading @@ -114,7 +114,7 @@ class BaseFormSet(object): return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max) else: initial_forms = self.initial_form_count() total_forms = initial_forms + self.extra total_forms = max(initial_forms, self.min_num) + self.extra # Allow all existing related objects/inlines to be displayed, # but don't allow extra beyond max_num. if initial_forms > self.max_num >= 0: Loading Loading @@ -158,8 +158,9 @@ class BaseFormSet(object): defaults['initial'] = self.initial[i] except IndexError: pass # Allow extra forms to be empty. if i >= self.initial_form_count(): # Allow extra forms to be empty, unless they're part of # the minimum forms. if i >= self.initial_form_count() and i >= self.min_num: defaults['empty_permitted'] = True defaults.update(kwargs) form = self.form(**defaults) Loading Loading @@ -422,7 +423,6 @@ def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, # limit is simply max_num + DEFAULT_MAX_NUM (which is 2*DEFAULT_MAX_NUM # if max_num is None in the first place) absolute_max = max_num + DEFAULT_MAX_NUM extra += min_num attrs = {'form': form, 'extra': extra, 'can_order': can_order, 'can_delete': can_delete, 'min_num': min_num, 'max_num': max_num, Loading tests/admin_inlines/tests.py +1 −2 Original line number Diff line number Diff line Loading @@ -247,7 +247,6 @@ class TestInline(TestCase): def test_custom_min_num(self): """ Ensure that get_min_num is called and used correctly. See #22628 - this will change when that's fixed. """ bt_head = BinaryTree.objects.create(name="Tree Head") BinaryTree.objects.create(name="First Child", parent=bt_head) Loading Loading @@ -277,7 +276,7 @@ class TestInline(TestCase): request.user = User(username='super', is_superuser=True) response = modeladmin.changeform_view(request, object_id=str(bt_head.id)) self.assertContains(response, min_forms % 5) self.assertContains(response, total_forms % 9) self.assertContains(response, total_forms % 8) def test_inline_nonauto_noneditable_pk(self): response = self.client.get('/admin/admin_inlines/author/add/') Loading tests/forms_tests/tests/test_formsets.py +5 −1 Original line number Diff line number Diff line Loading @@ -216,7 +216,7 @@ class FormsFormsetTestCase(TestCase): def test_min_num_displaying_more_than_one_blank_form(self): # We can also display more than 1 empty form passing min_num argument # to formset_factory. It will increment the extra argument # to formset_factory. It will (essentially) increment the extra argument ChoiceFormSet = formset_factory(Choice, extra=1, min_num=1) formset = ChoiceFormSet(auto_id=False, prefix='choices') Loading @@ -225,6 +225,10 @@ class FormsFormsetTestCase(TestCase): for form in formset.forms: form_output.append(form.as_ul()) # Min_num forms are required; extra forms can be empty. self.assertFalse(formset.forms[0].empty_permitted) self.assertTrue(formset.forms[1].empty_permitted) self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" /></li> <li>Votes: <input type="number" name="choices-0-votes" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li> Loading tests/generic_inline_admin/tests.py +2 −3 Original line number Diff line number Diff line Loading @@ -203,8 +203,7 @@ class GenericInlineAdminParametersTest(TestCase): def testMinNumParam(self): """ With extra=3 and min_num=2, there should be six forms. See #22628 - this will change when that's fixed. With extra=3 and min_num=2, there should be five forms. """ class MinNumInline(GenericTabularInline): model = Media Loading @@ -219,7 +218,7 @@ class GenericInlineAdminParametersTest(TestCase): request.user = User(username='super', is_superuser=True) response = modeladmin.changeform_view(request, object_id=str(e.pk)) formset = response.context_data['inline_admin_formsets'][0].formset self.assertEqual(formset.total_form_count(), 6) self.assertEqual(formset.total_form_count(), 5) self.assertEqual(formset.initial_form_count(), 1) Loading tests/model_formsets/tests.py +1 −2 Original line number Diff line number Diff line Loading @@ -385,13 +385,12 @@ class ModelFormsetTest(TestCase): def test_min_num_with_existing(self): # Test the behavior of min_num with existing objects. # See #22628 - this will change when that's fixed. Author.objects.create(name='Charles Baudelaire') qs = Author.objects.all() AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=0, min_num=1) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 2) self.assertEqual(len(formset.forms), 1) def test_custom_save_method(self): class PoetForm(forms.ModelForm): Loading Loading
django/forms/formsets.py +4 −4 Original line number Diff line number Diff line Loading @@ -114,7 +114,7 @@ class BaseFormSet(object): return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max) else: initial_forms = self.initial_form_count() total_forms = initial_forms + self.extra total_forms = max(initial_forms, self.min_num) + self.extra # Allow all existing related objects/inlines to be displayed, # but don't allow extra beyond max_num. if initial_forms > self.max_num >= 0: Loading Loading @@ -158,8 +158,9 @@ class BaseFormSet(object): defaults['initial'] = self.initial[i] except IndexError: pass # Allow extra forms to be empty. if i >= self.initial_form_count(): # Allow extra forms to be empty, unless they're part of # the minimum forms. if i >= self.initial_form_count() and i >= self.min_num: defaults['empty_permitted'] = True defaults.update(kwargs) form = self.form(**defaults) Loading Loading @@ -422,7 +423,6 @@ def formset_factory(form, formset=BaseFormSet, extra=1, can_order=False, # limit is simply max_num + DEFAULT_MAX_NUM (which is 2*DEFAULT_MAX_NUM # if max_num is None in the first place) absolute_max = max_num + DEFAULT_MAX_NUM extra += min_num attrs = {'form': form, 'extra': extra, 'can_order': can_order, 'can_delete': can_delete, 'min_num': min_num, 'max_num': max_num, Loading
tests/admin_inlines/tests.py +1 −2 Original line number Diff line number Diff line Loading @@ -247,7 +247,6 @@ class TestInline(TestCase): def test_custom_min_num(self): """ Ensure that get_min_num is called and used correctly. See #22628 - this will change when that's fixed. """ bt_head = BinaryTree.objects.create(name="Tree Head") BinaryTree.objects.create(name="First Child", parent=bt_head) Loading Loading @@ -277,7 +276,7 @@ class TestInline(TestCase): request.user = User(username='super', is_superuser=True) response = modeladmin.changeform_view(request, object_id=str(bt_head.id)) self.assertContains(response, min_forms % 5) self.assertContains(response, total_forms % 9) self.assertContains(response, total_forms % 8) def test_inline_nonauto_noneditable_pk(self): response = self.client.get('/admin/admin_inlines/author/add/') Loading
tests/forms_tests/tests/test_formsets.py +5 −1 Original line number Diff line number Diff line Loading @@ -216,7 +216,7 @@ class FormsFormsetTestCase(TestCase): def test_min_num_displaying_more_than_one_blank_form(self): # We can also display more than 1 empty form passing min_num argument # to formset_factory. It will increment the extra argument # to formset_factory. It will (essentially) increment the extra argument ChoiceFormSet = formset_factory(Choice, extra=1, min_num=1) formset = ChoiceFormSet(auto_id=False, prefix='choices') Loading @@ -225,6 +225,10 @@ class FormsFormsetTestCase(TestCase): for form in formset.forms: form_output.append(form.as_ul()) # Min_num forms are required; extra forms can be empty. self.assertFalse(formset.forms[0].empty_permitted) self.assertTrue(formset.forms[1].empty_permitted) self.assertHTMLEqual('\n'.join(form_output), """<li>Choice: <input type="text" name="choices-0-choice" /></li> <li>Votes: <input type="number" name="choices-0-votes" /></li> <li>Choice: <input type="text" name="choices-1-choice" /></li> Loading
tests/generic_inline_admin/tests.py +2 −3 Original line number Diff line number Diff line Loading @@ -203,8 +203,7 @@ class GenericInlineAdminParametersTest(TestCase): def testMinNumParam(self): """ With extra=3 and min_num=2, there should be six forms. See #22628 - this will change when that's fixed. With extra=3 and min_num=2, there should be five forms. """ class MinNumInline(GenericTabularInline): model = Media Loading @@ -219,7 +218,7 @@ class GenericInlineAdminParametersTest(TestCase): request.user = User(username='super', is_superuser=True) response = modeladmin.changeform_view(request, object_id=str(e.pk)) formset = response.context_data['inline_admin_formsets'][0].formset self.assertEqual(formset.total_form_count(), 6) self.assertEqual(formset.total_form_count(), 5) self.assertEqual(formset.initial_form_count(), 1) Loading
tests/model_formsets/tests.py +1 −2 Original line number Diff line number Diff line Loading @@ -385,13 +385,12 @@ class ModelFormsetTest(TestCase): def test_min_num_with_existing(self): # Test the behavior of min_num with existing objects. # See #22628 - this will change when that's fixed. Author.objects.create(name='Charles Baudelaire') qs = Author.objects.all() AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=0, min_num=1) formset = AuthorFormSet(queryset=qs) self.assertEqual(len(formset.forms), 2) self.assertEqual(len(formset.forms), 1) def test_custom_save_method(self): class PoetForm(forms.ModelForm): Loading