You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
561 lines
22 KiB
561 lines
22 KiB
# -*- coding: utf-8 -*- |
|
tests = """ |
|
# Basic FormSet creation and usage ############################################ |
|
|
|
FormSet allows us to use multiple instance of the same form on 1 page. For now, |
|
the best way to create a FormSet is by using the formset_factory function. |
|
|
|
>>> from django.forms import Form, CharField, IntegerField, ValidationError |
|
>>> from django.forms.formsets import formset_factory, BaseFormSet |
|
|
|
>>> class Choice(Form): |
|
... choice = CharField() |
|
... votes = IntegerField() |
|
|
|
>>> ChoiceFormSet = formset_factory(Choice) |
|
|
|
A FormSet constructor takes the same arguments as Form. Let's create a FormSet |
|
for adding data. By default, it displays 1 blank form. It can display more, |
|
but we'll look at how to do so later. |
|
|
|
>>> formset = ChoiceFormSet(auto_id=False, prefix='choices') |
|
>>> print formset |
|
<input type="hidden" name="choices-TOTAL_FORMS" value="1" /><input type="hidden" name="choices-INITIAL_FORMS" value="0" /> |
|
<tr><th>Choice:</th><td><input type="text" name="choices-0-choice" /></td></tr> |
|
<tr><th>Votes:</th><td><input type="text" name="choices-0-votes" /></td></tr> |
|
|
|
|
|
On thing to note is that there needs to be a special value in the data. This |
|
value tells the FormSet how many forms were displayed so it can tell how |
|
many forms it needs to clean and validate. You could use javascript to create |
|
new forms on the client side, but they won't get validated unless you increment |
|
the TOTAL_FORMS field appropriately. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '1', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... } |
|
|
|
We treat FormSet pretty much like we would treat a normal Form. FormSet has an |
|
is_valid method, and a cleaned_data or errors attribute depending on whether all |
|
the forms passed validation. However, unlike a Form instance, cleaned_data and |
|
errors will be a list of dicts rather than just a single dict. |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> [form.cleaned_data for form in formset.forms] |
|
[{'votes': 100, 'choice': u'Calexico'}] |
|
|
|
If a FormSet was not passed any data, its is_valid method should return False. |
|
>>> formset = ChoiceFormSet() |
|
>>> formset.is_valid() |
|
False |
|
|
|
FormSet instances can also have an error attribute if validation failed for |
|
any of the forms. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '1', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
False |
|
>>> formset.errors |
|
[{'votes': [u'This field is required.']}] |
|
|
|
|
|
We can also prefill a FormSet with existing data by providing an ``initial`` |
|
argument to the constructor. ``initial`` should be a list of dicts. By default, |
|
an extra blank form is included. |
|
|
|
>>> initial = [{'choice': u'Calexico', 'votes': 100}] |
|
>>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') |
|
>>> for form in formset.forms: |
|
... print form.as_ul() |
|
<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
|
<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
|
<li>Choice: <input type="text" name="choices-1-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-1-votes" /></li> |
|
|
|
|
|
Let's simulate what would happen if we submitted this form. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '2', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '1', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-1-choice': '', |
|
... 'choices-1-votes': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> [form.cleaned_data for form in formset.forms] |
|
[{'votes': 100, 'choice': u'Calexico'}, {}] |
|
|
|
But the second form was blank! Shouldn't we get some errors? No. If we display |
|
a form as blank, it's ok for it to be submitted as blank. If we fill out even |
|
one of the fields of a blank form though, it will be validated. We may want to |
|
required that at least x number of forms are completed, but we'll show how to |
|
handle that later. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '2', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '1', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-1-choice': 'The Decemberists', |
|
... 'choices-1-votes': '', # missing value |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
False |
|
>>> formset.errors |
|
[{}, {'votes': [u'This field is required.']}] |
|
|
|
If we delete data that was pre-filled, we should get an error. Simply removing |
|
data from form fields isn't the proper way to delete it. We'll see how to |
|
handle that case later. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '2', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '1', # the number of forms with initial data |
|
... 'choices-0-choice': '', # deleted value |
|
... 'choices-0-votes': '', # deleted value |
|
... 'choices-1-choice': '', |
|
... 'choices-1-votes': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
False |
|
>>> formset.errors |
|
[{'votes': [u'This field is required.'], 'choice': [u'This field is required.']}, {}] |
|
|
|
|
|
# Displaying more than 1 blank form ########################################### |
|
|
|
We can also display more than 1 empty form at a time. To do so, pass a |
|
extra argument to formset_factory. |
|
|
|
>>> ChoiceFormSet = formset_factory(Choice, extra=3) |
|
|
|
>>> formset = ChoiceFormSet(auto_id=False, prefix='choices') |
|
>>> for form in formset.forms: |
|
... print form.as_ul() |
|
<li>Choice: <input type="text" name="choices-0-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-0-votes" /></li> |
|
<li>Choice: <input type="text" name="choices-1-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-1-votes" /></li> |
|
<li>Choice: <input type="text" name="choices-2-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-2-votes" /></li> |
|
|
|
Since we displayed every form as blank, we will also accept them back as blank. |
|
This may seem a little strange, but later we will show how to require a minimum |
|
number of forms to be completed. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '3', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'choices-0-choice': '', |
|
... 'choices-0-votes': '', |
|
... 'choices-1-choice': '', |
|
... 'choices-1-votes': '', |
|
... 'choices-2-choice': '', |
|
... 'choices-2-votes': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> [form.cleaned_data for form in formset.forms] |
|
[{}, {}, {}] |
|
|
|
|
|
We can just fill out one of the forms. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '3', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-1-choice': '', |
|
... 'choices-1-votes': '', |
|
... 'choices-2-choice': '', |
|
... 'choices-2-votes': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> [form.cleaned_data for form in formset.forms] |
|
[{'votes': 100, 'choice': u'Calexico'}, {}, {}] |
|
|
|
|
|
And once again, if we try to partially complete a form, validation will fail. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '3', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-1-choice': 'The Decemberists', |
|
... 'choices-1-votes': '', # missing value |
|
... 'choices-2-choice': '', |
|
... 'choices-2-votes': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
False |
|
>>> formset.errors |
|
[{}, {'votes': [u'This field is required.']}, {}] |
|
|
|
|
|
The extra argument also works when the formset is pre-filled with initial |
|
data. |
|
|
|
>>> initial = [{'choice': u'Calexico', 'votes': 100}] |
|
>>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') |
|
>>> for form in formset.forms: |
|
... print form.as_ul() |
|
<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
|
<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
|
<li>Choice: <input type="text" name="choices-1-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-1-votes" /></li> |
|
<li>Choice: <input type="text" name="choices-2-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-2-votes" /></li> |
|
<li>Choice: <input type="text" name="choices-3-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-3-votes" /></li> |
|
|
|
|
|
# FormSets with deletion ###################################################### |
|
|
|
We can easily add deletion ability to a FormSet with an agrument to |
|
formset_factory. This will add a boolean field to each form instance. When |
|
that boolean field is True, the form will be in formset.deleted_forms |
|
|
|
>>> ChoiceFormSet = formset_factory(Choice, can_delete=True) |
|
|
|
>>> initial = [{'choice': u'Calexico', 'votes': 100}, {'choice': u'Fergie', 'votes': 900}] |
|
>>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') |
|
>>> for form in formset.forms: |
|
... print form.as_ul() |
|
<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
|
<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li> |
|
<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> |
|
<li>Votes: <input type="text" name="choices-1-votes" value="900" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li> |
|
<li>Choice: <input type="text" name="choices-2-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-2-votes" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li> |
|
|
|
To delete something, we just need to set that form's special delete field to |
|
'on'. Let's go ahead and delete Fergie. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '3', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '2', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-0-DELETE': '', |
|
... 'choices-1-choice': 'Fergie', |
|
... 'choices-1-votes': '900', |
|
... 'choices-1-DELETE': 'on', |
|
... 'choices-2-choice': '', |
|
... 'choices-2-votes': '', |
|
... 'choices-2-DELETE': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> [form.cleaned_data for form in formset.forms] |
|
[{'votes': 100, 'DELETE': False, 'choice': u'Calexico'}, {'votes': 900, 'DELETE': True, 'choice': u'Fergie'}, {}] |
|
>>> [form.cleaned_data for form in formset.deleted_forms] |
|
[{'votes': 900, 'DELETE': True, 'choice': u'Fergie'}] |
|
|
|
|
|
# FormSets with ordering ###################################################### |
|
|
|
We can also add ordering ability to a FormSet with an agrument to |
|
formset_factory. This will add a integer field to each form instance. When |
|
form validation succeeds, [form.cleaned_data for form in formset.forms] will have the data in the correct |
|
order specified by the ordering fields. If a number is duplicated in the set |
|
of ordering fields, for instance form 0 and form 3 are both marked as 1, then |
|
the form index used as a secondary ordering criteria. In order to put |
|
something at the front of the list, you'd need to set it's order to 0. |
|
|
|
>>> ChoiceFormSet = formset_factory(Choice, can_order=True) |
|
|
|
>>> initial = [{'choice': u'Calexico', 'votes': 100}, {'choice': u'Fergie', 'votes': 900}] |
|
>>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') |
|
>>> for form in formset.forms: |
|
... print form.as_ul() |
|
<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
|
<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
|
<li>Order: <input type="text" name="choices-0-ORDER" value="1" /></li> |
|
<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> |
|
<li>Votes: <input type="text" name="choices-1-votes" value="900" /></li> |
|
<li>Order: <input type="text" name="choices-1-ORDER" value="2" /></li> |
|
<li>Choice: <input type="text" name="choices-2-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-2-votes" /></li> |
|
<li>Order: <input type="text" name="choices-2-ORDER" /></li> |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '3', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '2', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-0-ORDER': '1', |
|
... 'choices-1-choice': 'Fergie', |
|
... 'choices-1-votes': '900', |
|
... 'choices-1-ORDER': '2', |
|
... 'choices-2-choice': 'The Decemberists', |
|
... 'choices-2-votes': '500', |
|
... 'choices-2-ORDER': '0', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> for form in formset.ordered_forms: |
|
... print form.cleaned_data |
|
{'votes': 500, 'ORDER': 0, 'choice': u'The Decemberists'} |
|
{'votes': 100, 'ORDER': 1, 'choice': u'Calexico'} |
|
{'votes': 900, 'ORDER': 2, 'choice': u'Fergie'} |
|
|
|
Ordering fields are allowed to be left blank, and if they *are* left blank, |
|
they will be sorted below everything else. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '4', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '3', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-0-ORDER': '1', |
|
... 'choices-1-choice': 'Fergie', |
|
... 'choices-1-votes': '900', |
|
... 'choices-1-ORDER': '2', |
|
... 'choices-2-choice': 'The Decemberists', |
|
... 'choices-2-votes': '500', |
|
... 'choices-2-ORDER': '', |
|
... 'choices-3-choice': 'Basia Bulat', |
|
... 'choices-3-votes': '50', |
|
... 'choices-3-ORDER': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> for form in formset.ordered_forms: |
|
... print form.cleaned_data |
|
{'votes': 100, 'ORDER': 1, 'choice': u'Calexico'} |
|
{'votes': 900, 'ORDER': 2, 'choice': u'Fergie'} |
|
{'votes': 500, 'ORDER': None, 'choice': u'The Decemberists'} |
|
{'votes': 50, 'ORDER': None, 'choice': u'Basia Bulat'} |
|
|
|
|
|
# FormSets with ordering + deletion ########################################### |
|
|
|
Let's try throwing ordering and deletion into the same form. |
|
|
|
>>> ChoiceFormSet = formset_factory(Choice, can_order=True, can_delete=True) |
|
|
|
>>> initial = [ |
|
... {'choice': u'Calexico', 'votes': 100}, |
|
... {'choice': u'Fergie', 'votes': 900}, |
|
... {'choice': u'The Decemberists', 'votes': 500}, |
|
... ] |
|
>>> formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') |
|
>>> for form in formset.forms: |
|
... print form.as_ul() |
|
<li>Choice: <input type="text" name="choices-0-choice" value="Calexico" /></li> |
|
<li>Votes: <input type="text" name="choices-0-votes" value="100" /></li> |
|
<li>Order: <input type="text" name="choices-0-ORDER" value="1" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-0-DELETE" /></li> |
|
<li>Choice: <input type="text" name="choices-1-choice" value="Fergie" /></li> |
|
<li>Votes: <input type="text" name="choices-1-votes" value="900" /></li> |
|
<li>Order: <input type="text" name="choices-1-ORDER" value="2" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-1-DELETE" /></li> |
|
<li>Choice: <input type="text" name="choices-2-choice" value="The Decemberists" /></li> |
|
<li>Votes: <input type="text" name="choices-2-votes" value="500" /></li> |
|
<li>Order: <input type="text" name="choices-2-ORDER" value="3" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-2-DELETE" /></li> |
|
<li>Choice: <input type="text" name="choices-3-choice" /></li> |
|
<li>Votes: <input type="text" name="choices-3-votes" /></li> |
|
<li>Order: <input type="text" name="choices-3-ORDER" /></li> |
|
<li>Delete: <input type="checkbox" name="choices-3-DELETE" /></li> |
|
|
|
Let's delete Fergie, and put The Decemberists ahead of Calexico. |
|
|
|
>>> data = { |
|
... 'choices-TOTAL_FORMS': '4', # the number of forms rendered |
|
... 'choices-INITIAL_FORMS': '3', # the number of forms with initial data |
|
... 'choices-0-choice': 'Calexico', |
|
... 'choices-0-votes': '100', |
|
... 'choices-0-ORDER': '1', |
|
... 'choices-0-DELETE': '', |
|
... 'choices-1-choice': 'Fergie', |
|
... 'choices-1-votes': '900', |
|
... 'choices-1-ORDER': '2', |
|
... 'choices-1-DELETE': 'on', |
|
... 'choices-2-choice': 'The Decemberists', |
|
... 'choices-2-votes': '500', |
|
... 'choices-2-ORDER': '0', |
|
... 'choices-2-DELETE': '', |
|
... 'choices-3-choice': '', |
|
... 'choices-3-votes': '', |
|
... 'choices-3-ORDER': '', |
|
... 'choices-3-DELETE': '', |
|
... } |
|
|
|
>>> formset = ChoiceFormSet(data, auto_id=False, prefix='choices') |
|
>>> formset.is_valid() |
|
True |
|
>>> for form in formset.ordered_forms: |
|
... print form.cleaned_data |
|
{'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': u'The Decemberists'} |
|
{'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': u'Calexico'} |
|
>>> [form.cleaned_data for form in formset.deleted_forms] |
|
[{'votes': 900, 'DELETE': True, 'ORDER': 2, 'choice': u'Fergie'}] |
|
|
|
|
|
# FormSet clean hook ########################################################## |
|
|
|
FormSets have a hook for doing extra validation that shouldn't be tied to any |
|
particular form. It follows the same pattern as the clean hook on Forms. |
|
|
|
Let's define a FormSet that takes a list of favorite drinks, but raises am |
|
error if there are any duplicates. |
|
|
|
>>> class FavoriteDrinkForm(Form): |
|
... name = CharField() |
|
... |
|
|
|
>>> class BaseFavoriteDrinksFormSet(BaseFormSet): |
|
... def clean(self): |
|
... seen_drinks = [] |
|
... for drink in self.cleaned_data: |
|
... if drink['name'] in seen_drinks: |
|
... raise ValidationError('You may only specify a drink once.') |
|
... seen_drinks.append(drink['name']) |
|
... |
|
|
|
>>> FavoriteDrinksFormSet = formset_factory(FavoriteDrinkForm, |
|
... formset=BaseFavoriteDrinksFormSet, extra=3) |
|
|
|
We start out with a some duplicate data. |
|
|
|
>>> data = { |
|
... 'drinks-TOTAL_FORMS': '2', # the number of forms rendered |
|
... 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'drinks-0-name': 'Gin and Tonic', |
|
... 'drinks-1-name': 'Gin and Tonic', |
|
... } |
|
|
|
>>> formset = FavoriteDrinksFormSet(data, prefix='drinks') |
|
>>> formset.is_valid() |
|
False |
|
|
|
Any errors raised by formset.clean() are available via the |
|
formset.non_form_errors() method. |
|
|
|
>>> for error in formset.non_form_errors(): |
|
... print error |
|
You may only specify a drink once. |
|
|
|
|
|
Make sure we didn't break the valid case. |
|
|
|
>>> data = { |
|
... 'drinks-TOTAL_FORMS': '2', # the number of forms rendered |
|
... 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data |
|
... 'drinks-0-name': 'Gin and Tonic', |
|
... 'drinks-1-name': 'Bloody Mary', |
|
... } |
|
|
|
>>> formset = FavoriteDrinksFormSet(data, prefix='drinks') |
|
>>> formset.is_valid() |
|
True |
|
>>> for error in formset.non_form_errors(): |
|
... print error |
|
|
|
# Limiting the maximum number of forms ######################################## |
|
|
|
# Base case for max_num. |
|
|
|
>>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=5, max_num=2) |
|
>>> formset = LimitedFavoriteDrinkFormSet() |
|
>>> for form in formset.forms: |
|
... print form |
|
<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr> |
|
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr> |
|
|
|
# Ensure the that max_num has no affect when extra is less than max_forms. |
|
|
|
>>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2) |
|
>>> formset = LimitedFavoriteDrinkFormSet() |
|
>>> for form in formset.forms: |
|
... print form |
|
<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" id="id_form-0-name" /></td></tr> |
|
|
|
# max_num with initial data |
|
|
|
# More initial forms than max_num will result in only the first max_num of |
|
# them to be displayed with no extra forms. |
|
|
|
>>> initial = [ |
|
... {'name': 'Gin Tonic'}, |
|
... {'name': 'Bloody Mary'}, |
|
... {'name': 'Jack and Coke'}, |
|
... ] |
|
>>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2) |
|
>>> formset = LimitedFavoriteDrinkFormSet(initial=initial) |
|
>>> for form in formset.forms: |
|
... print form |
|
<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name" /></td></tr> |
|
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" value="Bloody Mary" id="id_form-1-name" /></td></tr> |
|
|
|
# One form from initial and extra=3 with max_num=2 should result in the one |
|
# initial form and one extra. |
|
|
|
>>> initial = [ |
|
... {'name': 'Gin Tonic'}, |
|
... ] |
|
>>> LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=2) |
|
>>> formset = LimitedFavoriteDrinkFormSet(initial=initial) |
|
>>> for form in formset.forms: |
|
... print form |
|
<tr><th><label for="id_form-0-name">Name:</label></th><td><input type="text" name="form-0-name" value="Gin Tonic" id="id_form-0-name" /></td></tr> |
|
<tr><th><label for="id_form-1-name">Name:</label></th><td><input type="text" name="form-1-name" id="id_form-1-name" /></td></tr> |
|
|
|
|
|
# Regression test for #6926 ################################################## |
|
|
|
Make sure the management form has the correct prefix. |
|
|
|
>>> formset = FavoriteDrinksFormSet() |
|
>>> formset.management_form.prefix |
|
'form' |
|
|
|
>>> formset = FavoriteDrinksFormSet(data={}) |
|
>>> formset.management_form.prefix |
|
'form' |
|
|
|
>>> formset = FavoriteDrinksFormSet(initial={}) |
|
>>> formset.management_form.prefix |
|
'form' |
|
|
|
"""
|
|
|