mirror of https://github.com/django/django.git
[1.7.x] Fixed #22628 -- Took initial forms into account when combining FormSet.min_num and FormSet.extra.
This commit is contained in:
parent
6f0dcec44c
commit
79f15ab1ef
|
@ -114,7 +114,7 @@ class BaseFormSet(object):
|
||||||
return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
|
return min(self.management_form.cleaned_data[TOTAL_FORM_COUNT], self.absolute_max)
|
||||||
else:
|
else:
|
||||||
initial_forms = self.initial_form_count()
|
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,
|
# Allow all existing related objects/inlines to be displayed,
|
||||||
# but don't allow extra beyond max_num.
|
# but don't allow extra beyond max_num.
|
||||||
if initial_forms > self.max_num >= 0:
|
if initial_forms > self.max_num >= 0:
|
||||||
|
@ -158,8 +158,9 @@ class BaseFormSet(object):
|
||||||
defaults['initial'] = self.initial[i]
|
defaults['initial'] = self.initial[i]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
pass
|
pass
|
||||||
# Allow extra forms to be empty.
|
# Allow extra forms to be empty, unless they're part of
|
||||||
if i >= self.initial_form_count():
|
# the minimum forms.
|
||||||
|
if i >= self.initial_form_count() and i >= self.min_num:
|
||||||
defaults['empty_permitted'] = True
|
defaults['empty_permitted'] = True
|
||||||
defaults.update(kwargs)
|
defaults.update(kwargs)
|
||||||
form = self.form(**defaults)
|
form = self.form(**defaults)
|
||||||
|
@ -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
|
# limit is simply max_num + DEFAULT_MAX_NUM (which is 2*DEFAULT_MAX_NUM
|
||||||
# if max_num is None in the first place)
|
# if max_num is None in the first place)
|
||||||
absolute_max = max_num + DEFAULT_MAX_NUM
|
absolute_max = max_num + DEFAULT_MAX_NUM
|
||||||
extra += min_num
|
|
||||||
attrs = {'form': form, 'extra': extra,
|
attrs = {'form': form, 'extra': extra,
|
||||||
'can_order': can_order, 'can_delete': can_delete,
|
'can_order': can_order, 'can_delete': can_delete,
|
||||||
'min_num': min_num, 'max_num': max_num,
|
'min_num': min_num, 'max_num': max_num,
|
||||||
|
|
|
@ -247,7 +247,6 @@ class TestInline(TestCase):
|
||||||
def test_custom_min_num(self):
|
def test_custom_min_num(self):
|
||||||
"""
|
"""
|
||||||
Ensure that get_min_num is called and used correctly.
|
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")
|
bt_head = BinaryTree.objects.create(name="Tree Head")
|
||||||
BinaryTree.objects.create(name="First Child", parent=bt_head)
|
BinaryTree.objects.create(name="First Child", parent=bt_head)
|
||||||
|
@ -277,7 +276,7 @@ class TestInline(TestCase):
|
||||||
request.user = User(username='super', is_superuser=True)
|
request.user = User(username='super', is_superuser=True)
|
||||||
response = modeladmin.changeform_view(request, object_id=str(bt_head.id))
|
response = modeladmin.changeform_view(request, object_id=str(bt_head.id))
|
||||||
self.assertContains(response, min_forms % 5)
|
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):
|
def test_inline_nonauto_noneditable_pk(self):
|
||||||
response = self.client.get('/admin/admin_inlines/author/add/')
|
response = self.client.get('/admin/admin_inlines/author/add/')
|
||||||
|
|
|
@ -216,7 +216,7 @@ class FormsFormsetTestCase(TestCase):
|
||||||
|
|
||||||
def test_min_num_displaying_more_than_one_blank_form(self):
|
def test_min_num_displaying_more_than_one_blank_form(self):
|
||||||
# We can also display more than 1 empty form passing min_num argument
|
# 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)
|
ChoiceFormSet = formset_factory(Choice, extra=1, min_num=1)
|
||||||
|
|
||||||
formset = ChoiceFormSet(auto_id=False, prefix='choices')
|
formset = ChoiceFormSet(auto_id=False, prefix='choices')
|
||||||
|
@ -225,6 +225,10 @@ class FormsFormsetTestCase(TestCase):
|
||||||
for form in formset.forms:
|
for form in formset.forms:
|
||||||
form_output.append(form.as_ul())
|
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>
|
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>Votes: <input type="number" name="choices-0-votes" /></li>
|
||||||
<li>Choice: <input type="text" name="choices-1-choice" /></li>
|
<li>Choice: <input type="text" name="choices-1-choice" /></li>
|
||||||
|
|
|
@ -203,8 +203,7 @@ class GenericInlineAdminParametersTest(TestCase):
|
||||||
|
|
||||||
def testMinNumParam(self):
|
def testMinNumParam(self):
|
||||||
"""
|
"""
|
||||||
With extra=3 and min_num=2, there should be six forms.
|
With extra=3 and min_num=2, there should be five forms.
|
||||||
See #22628 - this will change when that's fixed.
|
|
||||||
"""
|
"""
|
||||||
class MinNumInline(GenericTabularInline):
|
class MinNumInline(GenericTabularInline):
|
||||||
model = Media
|
model = Media
|
||||||
|
@ -219,7 +218,7 @@ class GenericInlineAdminParametersTest(TestCase):
|
||||||
request.user = User(username='super', is_superuser=True)
|
request.user = User(username='super', is_superuser=True)
|
||||||
response = modeladmin.changeform_view(request, object_id=str(e.pk))
|
response = modeladmin.changeform_view(request, object_id=str(e.pk))
|
||||||
formset = response.context_data['inline_admin_formsets'][0].formset
|
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)
|
self.assertEqual(formset.initial_form_count(), 1)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -385,13 +385,12 @@ class ModelFormsetTest(TestCase):
|
||||||
|
|
||||||
def test_min_num_with_existing(self):
|
def test_min_num_with_existing(self):
|
||||||
# Test the behavior of min_num with existing objects.
|
# Test the behavior of min_num with existing objects.
|
||||||
# See #22628 - this will change when that's fixed.
|
|
||||||
Author.objects.create(name='Charles Baudelaire')
|
Author.objects.create(name='Charles Baudelaire')
|
||||||
qs = Author.objects.all()
|
qs = Author.objects.all()
|
||||||
|
|
||||||
AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=0, min_num=1)
|
AuthorFormSet = modelformset_factory(Author, fields="__all__", extra=0, min_num=1)
|
||||||
formset = AuthorFormSet(queryset=qs)
|
formset = AuthorFormSet(queryset=qs)
|
||||||
self.assertEqual(len(formset.forms), 2)
|
self.assertEqual(len(formset.forms), 1)
|
||||||
|
|
||||||
def test_custom_save_method(self):
|
def test_custom_save_method(self):
|
||||||
class PoetForm(forms.ModelForm):
|
class PoetForm(forms.ModelForm):
|
||||||
|
|
Loading…
Reference in New Issue