From e4ab44a4b2ef70be09c35c9197a19fd2e993b4d6 Mon Sep 17 00:00:00 2001 From: Mariusz Felisiak Date: Thu, 24 Sep 2020 09:45:51 +0200 Subject: [PATCH] Fixed #32038 -- Fixed EmptyFieldListFilter crash with GenericRelation. Thanks Javier Matos Odut for the report. --- django/contrib/contenttypes/fields.py | 4 ++++ docs/releases/3.1.2.txt | 3 +++ tests/admin_filters/tests.py | 26 ++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/django/contrib/contenttypes/fields.py b/django/contrib/contenttypes/fields.py index 3282fd6d4b..c0d085ffc2 100644 --- a/django/contrib/contenttypes/fields.py +++ b/django/contrib/contenttypes/fields.py @@ -277,6 +277,7 @@ class GenericRelation(ForeignObject): # Field flags auto_created = False + empty_strings_allowed = False many_to_many = False many_to_one = False @@ -295,6 +296,9 @@ class GenericRelation(ForeignObject): limit_choices_to=limit_choices_to, ) + # Reverse relations are always nullable (Django can't enforce that a + # foreign key on the related model points to this model). + kwargs['null'] = True kwargs['blank'] = True kwargs['on_delete'] = models.CASCADE kwargs['editable'] = False diff --git a/docs/releases/3.1.2.txt b/docs/releases/3.1.2.txt index 90ce6af97f..598bd2a754 100644 --- a/docs/releases/3.1.2.txt +++ b/docs/releases/3.1.2.txt @@ -23,3 +23,6 @@ Bugfixes * Fixed a bug in Django 3.1 where a test database was not synced during creation when using the :setting:`MIGRATE ` test database setting (:ticket:`32012`). + +* Fixed a ``django.contrib.admin.EmptyFieldListFilter`` crash when using on a + ``GenericRelation`` (:ticket:`32038`). diff --git a/tests/admin_filters/tests.py b/tests/admin_filters/tests.py index 6986afb64a..2ad44b6c8c 100644 --- a/tests/admin_filters/tests.py +++ b/tests/admin_filters/tests.py @@ -1535,6 +1535,32 @@ class ListFiltersTests(TestCase): queryset = changelist.get_queryset(request) self.assertCountEqual(queryset, expected_result) + def test_emptylistfieldfilter_genericrelation(self): + class BookmarkGenericRelation(ModelAdmin): + list_filter = ( + ('tags', EmptyFieldListFilter), + ) + + modeladmin = BookmarkGenericRelation(Bookmark, site) + + django_bookmark = Bookmark.objects.create(url='https://www.djangoproject.com/') + python_bookmark = Bookmark.objects.create(url='https://www.python.org/') + none_tags = Bookmark.objects.create(url='https://www.kernel.org/') + TaggedItem.objects.create(content_object=django_bookmark, tag='python') + TaggedItem.objects.create(content_object=python_bookmark, tag='python') + + tests = [ + ({'tags__isempty': '1'}, [none_tags]), + ({'tags__isempty': '0'}, [django_bookmark, python_bookmark]), + ] + for query_string, expected_result in tests: + with self.subTest(query_string=query_string): + request = self.request_factory.get('/', query_string) + request.user = self.alfred + changelist = modeladmin.get_changelist_instance(request) + queryset = changelist.get_queryset(request) + self.assertCountEqual(queryset, expected_result) + def test_emptylistfieldfilter_choices(self): modeladmin = BookAdminWithEmptyFieldListFilter(Book, site) request = self.request_factory.get('/')