diff --git a/django/test/testcases.py b/django/test/testcases.py index 0e4d406464..ddd9fe3c7f 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -572,7 +572,7 @@ class SimpleTestCase(unittest.TestCase): # Search all contexts for the error. found_formset = False for i, context in enumerate(contexts): - if formset not in context: + if formset not in context or not hasattr(context[formset], 'forms'): continue found_formset = True for err in errors: diff --git a/docs/releases/4.0.1.txt b/docs/releases/4.0.1.txt index d5a674778e..fa4ebe826f 100644 --- a/docs/releases/4.0.1.txt +++ b/docs/releases/4.0.1.txt @@ -9,4 +9,6 @@ Django 4.0.1 fixes several bugs in 4.0. Bugfixes ======== -* ... +* Fixed a regression in Django 4.0 that caused a crash of + :meth:`~django.test.SimpleTestCase.assertFormsetError` on a formset named + ``form`` (:ticket:`33346`). diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py index 47ce93e2ca..a2cb12c20e 100644 --- a/tests/test_utils/tests.py +++ b/tests/test_utils/tests.py @@ -1512,6 +1512,16 @@ class AssertFormsetErrorTests(SimpleTestCase): ]) self.assertFormsetError(response, 'formset', None, None, 'error') + def test_formset_named_form(self): + formset = TestFormset.invalid() + # The mocked context emulates the template-based rendering of the + # formset. + response = mock.Mock(context=[ + {'form': formset}, + {'form': formset.management_form}, + ]) + self.assertFormsetError(response, 'form', 0, 'field', 'invalid value') + class FirstUrls: urlpatterns = [path('first/', empty_response, name='first')]