diff --git a/tests/forms_tests/tests/test_formsets.py b/tests/forms_tests/tests/test_formsets.py index defa46b730..2346a826c2 100644 --- a/tests/forms_tests/tests/test_formsets.py +++ b/tests/forms_tests/tests/test_formsets.py @@ -16,8 +16,6 @@ class Choice(Form): votes = IntegerField() -# 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. ChoiceFormSet = formset_factory(Choice) @@ -36,25 +34,11 @@ class BaseFavoriteDrinksFormSet(BaseFormSet): seen_drinks.append(drink['name']) -class EmptyFsetWontValidate(BaseFormSet): - def clean(self): - raise ValidationError("Clean method called") - - -# Let's define a FormSet that takes a list of favorite drinks, but raises an -# error if there are any duplicates. Used in ``test_clean_hook``, -# ``test_regression_6926`` & ``test_regression_12878``. +# A FormSet that takes a list of favorite drinks and raises an error if +# there are any duplicates. FavoriteDrinksFormSet = formset_factory(FavoriteDrinkForm, formset=BaseFavoriteDrinksFormSet, extra=3) -# Used in ``test_formset_splitdatetimefield``. -class SplitDateTimeForm(Form): - when = SplitDateTimeField(initial=datetime.datetime.now) - - -SplitDateTimeFormSet = formset_factory(SplitDateTimeForm) - - class CustomKwargForm(Form): def __init__(self, *args, custom_kwarg, **kwargs): self.custom_kwarg = custom_kwarg @@ -96,9 +80,10 @@ class FormsFormsetTestCase(SimpleTestCase): return formset_class(data, **kwargs) def test_basic_formset(self): - # 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. + """ + A FormSet constructor takes the same arguments as Form. Create a + FormSet for adding data. By default, it displays 1 blank form. + """ formset = self.make_choiceformset() self.assertHTMLEqual( str(formset), @@ -109,18 +94,16 @@ class FormsFormsetTestCase(SimpleTestCase): Choice: Votes:""" ) - - # 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 are treated similarly to Forms. 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, cleaned_data + # and errors will be a list of dicts rather than a single dict. formset = self.make_choiceformset([('Calexico', '100')]) self.assertTrue(formset.is_valid()) self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'choice': 'Calexico'}]) - # If a FormSet was not passed any data, its is_valid and has_changed - # methods should return False. + # If a FormSet wasn't passed any data, is_valid() and has_changed() + # return False. formset = self.make_choiceformset() self.assertFalse(formset.is_valid()) self.assertFalse(formset.has_changed()) @@ -137,9 +120,7 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(form.custom_kwarg, 1) def test_form_kwargs_formset_dynamic(self): - """ - Form kwargs can be passed dynamically in a formset. - """ + """Form kwargs can be passed dynamically in a formset.""" class DynamicBaseFormSet(BaseFormSet): def get_form_kwargs(self, index): return {'custom_kwarg': index} @@ -190,33 +171,32 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(full_clean_counter.call_count, 4) def test_formset_has_changed(self): - # FormSet instances has_changed method will be True if any data is - # passed to his forms, even if the formset didn't validate + """ + FormSet.has_changed() is True if any data is passed to its forms, even + if the formset didn't validate. + """ blank_formset = self.make_choiceformset([('', '')]) self.assertFalse(blank_formset.has_changed()) - - # invalid formset test + # invalid formset invalid_formset = self.make_choiceformset([('Calexico', '')]) self.assertFalse(invalid_formset.is_valid()) self.assertTrue(invalid_formset.has_changed()) - - # valid formset test + # valid formset valid_formset = self.make_choiceformset([('Calexico', '100')]) self.assertTrue(valid_formset.is_valid()) self.assertTrue(valid_formset.has_changed()) def test_formset_initial_data(self): - # 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. - + """ + A FormSet can be prefilled with existing data by providing a list of + dicts to the `initial` argument. By default, an extra blank form is + included. + """ initial = [{'choice': 'Calexico', 'votes': 100}] formset = self.make_choiceformset(initial=initial) form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -225,25 +205,26 @@ class FormsFormsetTestCase(SimpleTestCase):
  • Votes:
  • """ ) - # Let's simulate what would happen if we submitted this form. + def test_blank_form_unfilled(self): + """A form that's displayed as blank may be submitted as blank.""" formset = self.make_choiceformset([('Calexico', '100'), ('', '')], initial_forms=1) self.assertTrue(formset.is_valid()) self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'choice': 'Calexico'}, {}]) def test_second_form_partially_filled(self): - # 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. + """ + If at least one field is filled out on a blank form, it will be + validated. + """ formset = self.make_choiceformset([('Calexico', '100'), ('The Decemberists', '')], initial_forms=1) self.assertFalse(formset.is_valid()) self.assertEqual(formset.errors, [{}, {'votes': ['This field is required.']}]) def test_delete_prefilled_data(self): - # 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. + """ + Deleting prefilled data is an error. Removing data from form fields + isn't the proper way to delete it. + """ formset = self.make_choiceformset([('', ''), ('', '')], initial_forms=1) self.assertFalse(formset.is_valid()) self.assertEqual( @@ -252,17 +233,15 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_displaying_more_than_one_blank_form(self): - # 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. + """ + More than 1 empty form can be displayed using formset_factory's + `extra` argument. + """ ChoiceFormSet = formset_factory(Choice, extra=3) - formset = ChoiceFormSet(auto_id=False, prefix='choices') form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -272,11 +251,9 @@ class FormsFormsetTestCase(SimpleTestCase):
  • Choice:
  • Votes:
  • """ ) - - # 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. - + # Since every form was displayed as blank, they are also accepted as + # blank. This may seem a little strange, but min_num is used 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 @@ -289,26 +266,23 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-2-choice': '', 'choices-2-votes': '', } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) self.assertEqual([form.cleaned_data for form in formset.forms], [{}, {}, {}]) 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 (essentially) increment the extra argument + """" + More than 1 empty form can also be displayed using formset_factory's + min_num argument. It will (essentially) increment the extra argument. + """ ChoiceFormSet = formset_factory(Choice, extra=1, min_num=1) - formset = ChoiceFormSet(auto_id=False, prefix='choices') form_output = [] - 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), """
  • Choice:
  • @@ -318,15 +292,12 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_min_num_displaying_more_than_one_blank_form_with_zero_extra(self): - # We can also display more than 1 empty form passing min_num argument + """More than 1 empty form can be displayed using min_num.""" ChoiceFormSet = formset_factory(Choice, extra=0, min_num=3) - formset = ChoiceFormSet(auto_id=False, prefix='choices') form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -338,8 +309,7 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_single_form_completed(self): - # We can just fill out one of the forms. - + """Just one form may be completed.""" data = { 'choices-TOTAL_FORMS': '3', # the number of forms rendered 'choices-INITIAL_FORMS': '0', # the number of forms with initial data @@ -352,18 +322,18 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-2-choice': '', 'choices-2-votes': '', } - ChoiceFormSet = formset_factory(Choice, extra=3) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) self.assertEqual([form.cleaned_data for form in formset.forms], [{'votes': 100, 'choice': 'Calexico'}, {}, {}]) def test_formset_validate_max_flag(self): - # If validate_max is set and max_num is less than TOTAL_FORMS in the - # data, then throw an exception. MAX_NUM_FORMS in the data is - # irrelevant here (it's output as a hint for the client but its - # value in the returned data is not checked) - + """ + If validate_max is set and max_num is less than TOTAL_FORMS in the + data, a ValidationError is raised. MAX_NUM_FORMS in the data is + irrelevant here (it's output as a hint for the client but its value + in the returned data is not checked). + """ data = { 'choices-TOTAL_FORMS': '2', # the number of forms rendered 'choices-INITIAL_FORMS': '0', # the number of forms with initial data @@ -374,18 +344,18 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-1-choice': 'One', 'choices-1-votes': '1', } - ChoiceFormSet = formset_factory(Choice, extra=1, max_num=1, validate_max=True) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertFalse(formset.is_valid()) self.assertEqual(formset.non_form_errors(), ['Please submit 1 or fewer forms.']) def test_formset_validate_min_flag(self): - # If validate_min is set and min_num is more than TOTAL_FORMS in the - # data, then throw an exception. MIN_NUM_FORMS in the data is - # irrelevant here (it's output as a hint for the client but its - # value in the returned data is not checked) - + """ + If validate_min is set and min_num is more than TOTAL_FORMS in the + data, a ValidationError is raised. MIN_NUM_FORMS in the data is + irrelevant here (it's output as a hint for the client but its value + in the returned data is not checked). + """ data = { 'choices-TOTAL_FORMS': '2', # the number of forms rendered 'choices-INITIAL_FORMS': '0', # the number of forms with initial data @@ -396,7 +366,6 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-1-choice': 'One', 'choices-1-votes': '1', } - ChoiceFormSet = formset_factory(Choice, extra=1, min_num=3, validate_min=True) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertFalse(formset.is_valid()) @@ -439,8 +408,7 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(formset.non_form_errors(), ['Please submit 1 or more forms.']) def test_second_form_partially_filled_2(self): - # And once again, if we try to partially complete a form, validation will fail. - + """A partially completed form is invalid.""" data = { 'choices-TOTAL_FORMS': '3', # the number of forms rendered 'choices-INITIAL_FORMS': '0', # the number of forms with initial data @@ -453,23 +421,22 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-2-choice': '', 'choices-2-votes': '', } - ChoiceFormSet = formset_factory(Choice, extra=3) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertFalse(formset.is_valid()) self.assertEqual(formset.errors, [{}, {'votes': ['This field is required.']}, {}]) def test_more_initial_data(self): - # The extra argument also works when the formset is pre-filled with initial - # data. + """ + The extra argument works when the formset is pre-filled with initial + data. + """ initial = [{'choice': 'Calexico', 'votes': 100}] ChoiceFormSet = formset_factory(Choice, extra=3) formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -481,9 +448,7 @@ class FormsFormsetTestCase(SimpleTestCase):
  • Choice:
  • Votes:
  • """ ) - - # Make sure retrieving an empty form works, and it shows up in the form list - + # Retrieving an empty form works. Tt shows up in the form list. self.assertTrue(formset.empty_form.empty_permitted) self.assertHTMLEqual( formset.empty_form.as_ul(), @@ -492,20 +457,17 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_formset_with_deletion(self): - # FormSets with deletion ###################################################### - # We can easily add deletion ability to a FormSet with an argument 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 - + """ + formset_factory's can_delete argument adds a boolean "delete" field to + each form. When that boolean field is True, the form will be in + formset.deleted_forms. + """ ChoiceFormSet = formset_factory(Choice, can_delete=True) - initial = [{'choice': 'Calexico', 'votes': 100}, {'choice': 'Fergie', 'votes': 900}] formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -518,10 +480,8 @@ class FormsFormsetTestCase(SimpleTestCase):
  • Votes:
  • Delete:
  • """ ) - - # To delete something, we just need to set that form's special delete field to - # 'on'. Let's go ahead and delete Fergie. - + # To delete something, 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 @@ -537,7 +497,6 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-2-votes': '', 'choices-2-DELETE': '', } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) self.assertEqual( @@ -553,10 +512,12 @@ class FormsFormsetTestCase(SimpleTestCase): [{'votes': 900, 'DELETE': True, 'choice': 'Fergie'}] ) - # If we fill a form with something and then we check the can_delete checkbox for - # that form, that form's errors should not make the entire formset invalid since - # it's going to be deleted. - + def test_formset_with_deletion_remove_deletion_flag(self): + """ + If a form is filled with something and can_delete is also checked, that + form's errors shouldn't make the entire formset invalid since it's + going to be deleted. + """ class CheckForm(Form): field = IntegerField(min_value=100) @@ -575,50 +536,48 @@ class FormsFormsetTestCase(SimpleTestCase): CheckFormSet = formset_factory(CheckForm, can_delete=True) formset = CheckFormSet(data, prefix='check') self.assertTrue(formset.is_valid()) - - # If we remove the deletion flag now we will have our validation back. + # If the deletion flag is removed, validation is enabled. data['check-1-DELETE'] = '' formset = CheckFormSet(data, prefix='check') self.assertFalse(formset.is_valid()) - # Should be able to get deleted_forms from a valid formset even if a - # deleted form would have been invalid. - + def test_formset_with_deletion_invalid_deleted_form(self): + """ + deleted_forms works on a valid formset even if a deleted form would + have been invalid. + """ class Person(Form): name = CharField() - PeopleForm = formset_factory( - form=Person, - can_delete=True) - - p = PeopleForm( - {'form-0-name': '', 'form-0-DELETE': 'on', # no name! - 'form-TOTAL_FORMS': 1, 'form-INITIAL_FORMS': 1, - 'form-MIN_NUM_FORMS': 0, 'form-MAX_NUM_FORMS': 1}) - + PeopleForm = formset_factory(form=Person, can_delete=True) + p = PeopleForm({ + 'form-0-name': '', + 'form-0-DELETE': 'on', # no name! + 'form-TOTAL_FORMS': 1, + 'form-INITIAL_FORMS': 1, + 'form-MIN_NUM_FORMS': 0, + 'form-MAX_NUM_FORMS': 1}, + ) self.assertTrue(p.is_valid()) self.assertEqual(p._errors, []) self.assertEqual(len(p.deleted_forms), 1) def test_formsets_with_ordering(self): - # FormSets with ordering ###################################################### - # We can also add ordering ability to a FormSet with an argument to - # formset_factory. This will add an 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. - + """ + formset_factory's can_order argument adds an integer field to each + form. 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 its order to 0. + """ ChoiceFormSet = formset_factory(Choice, can_order=True) - initial = [{'choice': 'Calexico', 'votes': 100}, {'choice': 'Fergie', 'votes': 900}] formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -631,7 +590,6 @@ class FormsFormsetTestCase(SimpleTestCase):
  • Votes:
  • Order:
  • """ ) - data = { 'choices-TOTAL_FORMS': '3', # the number of forms rendered 'choices-INITIAL_FORMS': '2', # the number of forms with initial data @@ -651,10 +609,8 @@ class FormsFormsetTestCase(SimpleTestCase): formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) form_output = [] - for form in formset.ordered_forms: form_output.append(form.cleaned_data) - self.assertEqual(form_output, [ {'votes': 500, 'ORDER': 0, 'choice': 'The Decemberists'}, {'votes': 100, 'ORDER': 1, 'choice': 'Calexico'}, @@ -662,9 +618,10 @@ class FormsFormsetTestCase(SimpleTestCase): ]) def test_empty_ordered_fields(self): - # Ordering fields are allowed to be left blank, and if they *are* left blank, - # they will be sorted below everything else. - + """ + Ordering fields are allowed to be left blank. If they are left blank, + they'll 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 @@ -683,15 +640,12 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-3-votes': '50', 'choices-3-ORDER': '', } - ChoiceFormSet = formset_factory(Choice, can_order=True) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) form_output = [] - for form in formset.ordered_forms: form_output.append(form.cleaned_data) - self.assertEqual(form_output, [ {'votes': 100, 'ORDER': 1, 'choice': 'Calexico'}, {'votes': 900, 'ORDER': 2, 'choice': 'Fergie'}, @@ -700,29 +654,23 @@ class FormsFormsetTestCase(SimpleTestCase): ]) def test_ordering_blank_fieldsets(self): - # Ordering should work with blank fieldsets. - + """Ordering works with blank fieldsets.""" data = { 'choices-TOTAL_FORMS': '3', # the number of forms rendered 'choices-INITIAL_FORMS': '0', # the number of forms with initial data 'choices-MIN_NUM_FORMS': '0', # min number of forms 'choices-MAX_NUM_FORMS': '0', # max number of forms } - ChoiceFormSet = formset_factory(Choice, can_order=True) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) form_output = [] - for form in formset.ordered_forms: form_output.append(form.cleaned_data) - self.assertEqual(form_output, []) def test_formset_with_ordering_and_deletion(self): - # FormSets with ordering + deletion ########################################### - # Let's try throwing ordering and deletion into the same form. - + """FormSets with ordering + deletion.""" ChoiceFormSet = formset_factory(Choice, can_order=True, can_delete=True) initial = [ @@ -732,10 +680,8 @@ class FormsFormsetTestCase(SimpleTestCase): ] formset = ChoiceFormSet(initial=initial, auto_id=False, prefix='choices') form_output = [] - for form in formset.forms: form_output.append(form.as_ul()) - self.assertHTMLEqual( '\n'.join(form_output), """
  • Choice:
  • @@ -755,9 +701,7 @@ class FormsFormsetTestCase(SimpleTestCase):
  • Order:
  • Delete:
  • """ ) - # 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 @@ -780,14 +724,11 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-3-ORDER': '', 'choices-3-DELETE': '', } - formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertTrue(formset.is_valid()) form_output = [] - for form in formset.ordered_forms: form_output.append(form.cleaned_data) - self.assertEqual(form_output, [ {'votes': 500, 'DELETE': False, 'ORDER': 0, 'choice': 'The Decemberists'}, {'votes': 100, 'DELETE': False, 'ORDER': 1, 'choice': 'Calexico'}, @@ -798,14 +739,14 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_invalid_deleted_form_with_ordering(self): - # Should be able to get ordered forms from a valid formset even if a - # deleted form would have been invalid. - + """ + Can get ordered_forms from a valid formset even if a deleted form + would have been invalid. + """ class Person(Form): name = CharField() PeopleForm = formset_factory(form=Person, can_delete=True, can_order=True) - p = PeopleForm({ 'form-0-name': '', 'form-0-DELETE': 'on', # no name! @@ -814,17 +755,15 @@ class FormsFormsetTestCase(SimpleTestCase): 'form-MIN_NUM_FORMS': 0, 'form-MAX_NUM_FORMS': 1 }) - self.assertTrue(p.is_valid()) self.assertEqual(p.ordered_forms, []) def test_clean_hook(self): - # 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. - - # We start out with a some duplicate data. - + """ + FormSets have a clean() hook for doing extra validation that isn't tied + to any form. It follows the same pattern as the clean() hook on Forms. + """ + # 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 @@ -833,18 +772,13 @@ class FormsFormsetTestCase(SimpleTestCase): 'drinks-0-name': 'Gin and Tonic', 'drinks-1-name': 'Gin and Tonic', } - formset = FavoriteDrinksFormSet(data, prefix='drinks') self.assertFalse(formset.is_valid()) - # Any errors raised by formset.clean() are available via the # formset.non_form_errors() method. - for error in formset.non_form_errors(): self.assertEqual(str(error), 'You may only specify a drink once.') - - # Make sure we didn't break the valid case. - + # The valid case still works. data = { 'drinks-TOTAL_FORMS': '2', # the number of forms rendered 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data @@ -853,25 +787,19 @@ class FormsFormsetTestCase(SimpleTestCase): 'drinks-0-name': 'Gin and Tonic', 'drinks-1-name': 'Bloody Mary', } - formset = FavoriteDrinksFormSet(data, prefix='drinks') self.assertTrue(formset.is_valid()) self.assertEqual(formset.non_form_errors(), []) def test_limiting_max_forms(self): - # Limiting the maximum number of forms ######################################## - # Base case for max_num. - + """Limiting the maximum number of forms with max_num.""" # When not passed, max_num will take a high default value, leaving the # number of forms only controlled by the value of the extra parameter. - LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3) formset = LimitedFavoriteDrinkFormSet() form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertHTMLEqual( '\n'.join(form_output), """ @@ -881,24 +809,20 @@ class FormsFormsetTestCase(SimpleTestCase): """ ) - # If max_num is 0 then no form is rendered at all. LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=3, max_num=0) formset = LimitedFavoriteDrinkFormSet() form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertEqual('\n'.join(form_output), "") + def test_limited_max_forms_two(self): LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=5, max_num=2) formset = LimitedFavoriteDrinkFormSet() form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertHTMLEqual( '\n'.join(form_output), """ @@ -907,14 +831,13 @@ class FormsFormsetTestCase(SimpleTestCase): """ ) - # max_num has no effect when extra is less than max_num. + def test_limiting_extra_lest_than_max_num(self): + """max_num has no effect when extra is less than max_num.""" LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2) formset = LimitedFavoriteDrinkFormSet() form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertHTMLEqual( '\n'.join(form_output), """ @@ -922,22 +845,18 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_max_num_with_initial_data(self): - # max_num with initial data - + """max_num with initial data.""" # When not passed, max_num will take a high default value, leaving the # number of forms only controlled by the value of the initial and extra # parameters. - initial = [ {'name': 'Fernet and Coke'}, ] LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1) formset = LimitedFavoriteDrinkFormSet(initial=initial) form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertHTMLEqual( '\n'.join(form_output), """ @@ -947,21 +866,19 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_max_num_zero(self): - # If max_num is 0 then no form is rendered at all, regardless of extra, - # unless initial data is present. (This changed in the patch for bug - # 20084 -- previously max_num=0 trumped initial data) - + """ + If max_num is 0 then no form is rendered at all, regardless of extra, + unless initial data is present. + """ LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=0) formset = LimitedFavoriteDrinkFormSet() form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertEqual('\n'.join(form_output), "") - # test that initial trumps max_num - + def test_max_num_zero_with_initial(self): + # initial trumps max_num initial = [ {'name': 'Fernet and Coke'}, {'name': 'Bloody Mary'}, @@ -969,7 +886,6 @@ class FormsFormsetTestCase(SimpleTestCase): LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=0) formset = LimitedFavoriteDrinkFormSet(initial=initial) form_output = [] - for form in formset.forms: form_output.append(str(form)) self.assertHTMLEqual( @@ -981,10 +897,10 @@ class FormsFormsetTestCase(SimpleTestCase): ) def test_more_initial_than_max_num(self): - # More initial forms than max_num now results in all initial forms - # being displayed (but no extra forms). This behavior was changed - # from max_num taking precedence in the patch for #20084 - + """ + More initial forms than max_num results in all initial forms being + displayed (but no extra forms). + """ initial = [ {'name': 'Gin Tonic'}, {'name': 'Bloody Mary'}, @@ -993,7 +909,6 @@ class FormsFormsetTestCase(SimpleTestCase): LimitedFavoriteDrinkFormSet = formset_factory(FavoriteDrinkForm, extra=1, max_num=2) formset = LimitedFavoriteDrinkFormSet(initial=initial) form_output = [] - for form in formset.forms: form_output.append(str(form)) self.assertHTMLEqual( @@ -1006,18 +921,19 @@ class FormsFormsetTestCase(SimpleTestCase): """ ) - # One form from initial and extra=3 with max_num=2 should result in the one - # initial form and one extra. + def test_more_initial_form_result_in_one(self): + """ + One form from initial and extra=3 with max_num=2 results 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) form_output = [] - for form in formset.forms: form_output.append(str(form)) - self.assertHTMLEqual( '\n'.join(form_output), """ @@ -1026,13 +942,10 @@ class FormsFormsetTestCase(SimpleTestCase): """ ) - def test_regression_6926(self): - # Regression test for #6926 ################################################## - # Make sure the management form has the correct prefix. - + def test_management_form_prefix(self): + """The management form has the correct prefix.""" formset = FavoriteDrinksFormSet() self.assertEqual(formset.management_form.prefix, 'form') - data = { 'form-TOTAL_FORMS': '2', 'form-INITIAL_FORMS': '0', @@ -1041,13 +954,10 @@ class FormsFormsetTestCase(SimpleTestCase): } formset = FavoriteDrinksFormSet(data=data) self.assertEqual(formset.management_form.prefix, 'form') - formset = FavoriteDrinksFormSet(initial={}) self.assertEqual(formset.management_form.prefix, 'form') - def test_regression_12878(self): - # Regression test for #12878 ################################################# - + def test_non_form_errors(self): data = { 'drinks-TOTAL_FORMS': '2', # the number of forms rendered 'drinks-INITIAL_FORMS': '0', # the number of forms with initial data @@ -1056,22 +966,19 @@ class FormsFormsetTestCase(SimpleTestCase): 'drinks-0-name': 'Gin and Tonic', 'drinks-1-name': 'Gin and Tonic', } - formset = FavoriteDrinksFormSet(data, prefix='drinks') self.assertFalse(formset.is_valid()) self.assertEqual(formset.non_form_errors(), ['You may only specify a drink once.']) def test_formset_iteration(self): - # Regression tests for #16455 -- formset instances are iterable + """Formset instances are iterable.""" ChoiceFormset = formset_factory(Choice, extra=3) formset = ChoiceFormset() - - # confirm iterated formset yields formset.forms + # An iterated formset yields formset.forms. forms = list(formset) self.assertEqual(forms, formset.forms) self.assertEqual(len(formset), len(forms)) - - # confirm indexing of formset + # A formset may be indexed to retrieve its forms. self.assertEqual(formset[0], forms[0]) with self.assertRaises(IndexError): formset[3] @@ -1086,18 +993,14 @@ class FormsFormsetTestCase(SimpleTestCase): ReverseChoiceFormset = formset_factory(Choice, BaseReverseFormSet, extra=3) reverse_formset = ReverseChoiceFormset() - - # confirm that __iter__ modifies rendering order - # compare forms from "reverse" formset with forms from original formset + # __iter__() modifies the rendering order. + # Compare forms from "reverse" formset with forms from original formset self.assertEqual(str(reverse_formset[0]), str(forms[-1])) self.assertEqual(str(reverse_formset[1]), str(forms[-2])) self.assertEqual(len(reverse_formset), len(forms)) def test_formset_nonzero(self): - """ - Formsets with no forms should still evaluate as true. - Regression test for #15722 - """ + """A formsets without any forms evaluates as True.""" ChoiceFormset = formset_factory(Choice, extra=0) formset = ChoiceFormset() self.assertEqual(len(formset.forms), 0) @@ -1105,9 +1008,12 @@ class FormsFormsetTestCase(SimpleTestCase): def test_formset_splitdatetimefield(self): """ - Formset should also work with SplitDateTimeField(initial=datetime.datetime.now). - Regression test for #18709. + Formset works with SplitDateTimeField(initial=datetime.datetime.now). """ + class SplitDateTimeForm(Form): + when = SplitDateTimeField(initial=datetime.datetime.now) + + SplitDateTimeFormSet = formset_factory(SplitDateTimeForm) data = { 'form-TOTAL_FORMS': '1', 'form-INITIAL_FORMS': '0', @@ -1118,7 +1024,7 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertTrue(formset.is_valid()) def test_formset_error_class(self): - # Regression tests for #16479 -- formsets form use ErrorList instead of supplied error_class + """Formset's forms use the formset's error_class.""" class CustomErrorList(ErrorList): pass @@ -1126,9 +1032,7 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(formset.forms[0].error_class, CustomErrorList) def test_formset_calls_forms_is_valid(self): - # Regression tests for #18574 -- make sure formsets call - # is_valid() on each form. - + """Formsets call is_valid() on each form.""" class AnotherChoice(Choice): def is_valid(self): self.is_valid_called = True @@ -1210,9 +1114,10 @@ class FormsFormsetTestCase(SimpleTestCase): formsets.DEFAULT_MAX_NUM = _old_DEFAULT_MAX_NUM def test_non_form_errors_run_full_clean(self): - # Regression test for #11160 - # If non_form_errors() is called without calling is_valid() first, - # it should ensure that full_clean() is called. + """ + If non_form_errors() is called without calling is_valid() first, + it should ensure that full_clean() is called. + """ class BaseCustomFormSet(BaseFormSet): def clean(self): raise ValidationError("This is a non-form error") @@ -1235,8 +1140,7 @@ class FormsFormsetTestCase(SimpleTestCase): 'check-1-field': '50', 'check-1-DELETE': 'on', } - CheckFormSet = formset_factory(CheckForm, max_num=1, validate_max=True, - can_delete=True) + CheckFormSet = formset_factory(CheckForm, max_num=1, validate_max=True, can_delete=True) formset = CheckFormSet(data, prefix='check') self.assertTrue(formset.is_valid()) @@ -1249,7 +1153,6 @@ class FormsFormsetTestCase(SimpleTestCase): ([('Calexico', '100'), ('Calexico', '')], 1), ([('Calexico', ''), ('Calexico', '')], 2), ] - for formset_data, expected_error_count in data: formset = self.make_choiceformset(formset_data) self.assertEqual(formset.total_error_count(), expected_error_count) @@ -1264,11 +1167,9 @@ class FormsFormsetTestCase(SimpleTestCase): 'choices-1-choice': 'One', 'choices-1-votes': '1', } - ChoiceFormSet = formset_factory(Choice, extra=1, max_num=1, validate_max=True) formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertEqual(formset.total_error_count(), 1) - data['choices-1-votes'] = '' formset = ChoiceFormSet(data, auto_id=False, prefix='choices') self.assertEqual(formset.total_error_count(), 2) @@ -1327,7 +1228,6 @@ class FormsetAsFooTests(SimpleTestCase): ) -# Regression test for #11418 ################################################# class ArticleForm(Form): title = CharField() pub_date = DateField() @@ -1378,16 +1278,13 @@ class TestIsBoundBehavior(SimpleTestCase): } unbound_formset = ArticleFormSet() bound_formset = ArticleFormSet(data) - empty_forms = [ unbound_formset.empty_form, bound_formset.empty_form ] - # Empty forms should be unbound self.assertFalse(empty_forms[0].is_bound) self.assertFalse(empty_forms[1].is_bound) - # The empty forms should be equal. self.assertHTMLEqual(empty_forms[0].as_p(), empty_forms[1].as_p()) @@ -1395,6 +1292,10 @@ class TestIsBoundBehavior(SimpleTestCase): class TestEmptyFormSet(SimpleTestCase): def test_empty_formset_is_valid(self): """An empty formset still calls clean()""" + class EmptyFsetWontValidate(BaseFormSet): + def clean(self): + raise ValidationError('Clean method called') + EmptyFsetWontValidateFormset = formset_factory(FavoriteDrinkForm, extra=0, formset=EmptyFsetWontValidate) formset = EmptyFsetWontValidateFormset( data={'form-INITIAL_FORMS': '0', 'form-TOTAL_FORMS': '0'}, @@ -1408,14 +1309,14 @@ class TestEmptyFormSet(SimpleTestCase): self.assertFalse(formset2.is_valid()) def test_empty_formset_media(self): - """Make sure media is available on empty formset, refs #19545""" + """Media is available on empty formset.""" class MediaForm(Form): class Media: js = ('some-file.js',) self.assertIn('some-file.js', str(formset_factory(MediaForm, extra=0)().media)) def test_empty_formset_is_multipart(self): - """Make sure `is_multipart()` works with empty formset, refs #19545""" + """is_multipart() works with an empty formset.""" class FileForm(Form): file = FileField() self.assertTrue(formset_factory(FileForm, extra=0)().is_multipart())