diff options
| author | Baptiste Mispelon <bmispelon@gmail.com> | 2021-12-11 20:17:29 +0100 |
|---|---|---|
| committer | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2021-12-21 12:06:05 +0100 |
| commit | e95e6425ac354b8fb0c24580b740dbdc2ea72bd6 (patch) | |
| tree | abdadc46924748086d6788364f747abb76551029 | |
| parent | 61b332499d28afe1c7d413411166ad405663e750 (diff) | |
Refs #24121 -- Added __repr__() to BaseFormSet.
| -rw-r--r-- | django/forms/formsets.py | 16 | ||||
| -rw-r--r-- | tests/forms_tests/tests/test_formsets.py | 63 |
2 files changed, 79 insertions, 0 deletions
diff --git a/django/forms/formsets.py b/django/forms/formsets.py index aca518b4d2..75b0646512 100644 --- a/django/forms/formsets.py +++ b/django/forms/formsets.py @@ -103,6 +103,22 @@ class BaseFormSet(RenderableFormMixin): """ return True + def __repr__(self): + if self._errors is None: + is_valid = 'Unknown' + else: + is_valid = ( + self.is_bound and + not self._non_form_errors and + not any(form_errors for form_errors in self._errors) + ) + return '<%s: bound=%s valid=%s total_forms=%s>' % ( + self.__class__.__qualname__, + self.is_bound, + is_valid, + self.total_form_count(), + ) + @cached_property def management_form(self): """Return the ManagementForm instance for this FormSet.""" diff --git a/tests/forms_tests/tests/test_formsets.py b/tests/forms_tests/tests/test_formsets.py index 1705d8bb6b..50342cfaa9 100644 --- a/tests/forms_tests/tests/test_formsets.py +++ b/tests/forms_tests/tests/test_formsets.py @@ -25,6 +25,12 @@ class Choice(Form): ChoiceFormSet = formset_factory(Choice) +class ChoiceFormsetWithNonFormError(ChoiceFormSet): + def clean(self): + super().clean() + raise ValidationError('non-form error') + + class FavoriteDrinkForm(Form): name = CharField() @@ -1328,6 +1334,63 @@ class FormsFormsetTestCase(SimpleTestCase): self.assertEqual(formset.non_form_errors().renderer, renderer) self.assertEqual(formset.empty_form.renderer, renderer) + def test_repr(self): + valid_formset = self.make_choiceformset([('test', 1)]) + valid_formset.full_clean() + invalid_formset = self.make_choiceformset([('test', '')]) + invalid_formset.full_clean() + partially_invalid_formset = self.make_choiceformset( + [('test', '1'), ('test', '')], + ) + partially_invalid_formset.full_clean() + invalid_formset_non_form_errors_only = self.make_choiceformset( + [('test', '')], + formset_class=ChoiceFormsetWithNonFormError, + ) + invalid_formset_non_form_errors_only.full_clean() + + cases = [ + ( + self.make_choiceformset(), + '<ChoiceFormSet: bound=False valid=Unknown total_forms=1>', + ), + ( + self.make_choiceformset( + formset_class=formset_factory(Choice, extra=10), + ), + '<ChoiceFormSet: bound=False valid=Unknown total_forms=10>', + ), + ( + self.make_choiceformset([]), + '<ChoiceFormSet: bound=True valid=Unknown total_forms=0>', + ), + ( + self.make_choiceformset([('test', 1)]), + '<ChoiceFormSet: bound=True valid=Unknown total_forms=1>', + ), + (valid_formset, '<ChoiceFormSet: bound=True valid=True total_forms=1>'), + (invalid_formset, '<ChoiceFormSet: bound=True valid=False total_forms=1>'), + ( + partially_invalid_formset, + '<ChoiceFormSet: bound=True valid=False total_forms=2>', + ), + ( + invalid_formset_non_form_errors_only, + '<ChoiceFormsetWithNonFormError: bound=True valid=False total_forms=1>', + ), + ] + for formset, expected_repr in cases: + with self.subTest(expected_repr=expected_repr): + self.assertEqual(repr(formset), expected_repr) + + def test_repr_do_not_trigger_validation(self): + formset = self.make_choiceformset([('test', 1)]) + with mock.patch.object(formset, 'full_clean') as mocked_full_clean: + repr(formset) + mocked_full_clean.assert_not_called() + formset.is_valid() + mocked_full_clean.assert_called() + @jinja2_tests class Jinja2FormsFormsetTestCase(FormsFormsetTestCase): |
