From 8db593de05c3516c939b7d4b9eb91e8791f4c79a Mon Sep 17 00:00:00 2001 From: Hisham Mahmood <45965466+Hisham-Pak@users.noreply.github.com> Date: Thu, 15 Feb 2024 06:29:49 +0500 Subject: [PATCH] Fixed #35173 -- Fixed ModelAdmin.lookup_allowed() for lookups on foreign keys when not included in ModelAdmin.list_filter. Regression in f80669d2f5a5f1db9e9b73ca893fefba34f955e7. Thanks Sarah Boyce for the review. --- django/contrib/admin/options.py | 23 ++++++++++++----------- docs/releases/5.0.3.txt | 5 +++++ tests/modeladmin/tests.py | 14 +++++++++++++- 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index d97597fe66d..e93fdf40475 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -475,24 +475,25 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): # Lookups on nonexistent fields are ok, since they're ignored # later. break + if not prev_field or ( + prev_field.is_relation + and field not in model._meta.parents.values() + and field is not model._meta.auto_field + and ( + model._meta.auto_field is None + or part not in getattr(prev_field, "to_fields", []) + ) + and (field.is_relation or not field.primary_key) + ): + relation_parts.append(part) if not getattr(field, "path_infos", None): # This is not a relational field, so further parts # must be transforms. break - if ( - not prev_field - or (field.is_relation and field not in model._meta.parents.values()) - or ( - prev_field.is_relation - and model._meta.auto_field is None - and part not in getattr(prev_field, "to_fields", []) - ) - ): - relation_parts.append(part) prev_field = field model = field.path_infos[-1].to_opts.model - if not relation_parts or len(parts) == 1: + if len(relation_parts) <= 1: # Either a local field filter, or no fields at all. return True valid_lookups = {self.date_hierarchy} diff --git a/docs/releases/5.0.3.txt b/docs/releases/5.0.3.txt index 30e87127b0b..b433bf6f2fe 100644 --- a/docs/releases/5.0.3.txt +++ b/docs/releases/5.0.3.txt @@ -15,3 +15,8 @@ Bugfixes * Fixed a bug in Django 5.0 that caused a crash of ``Signal.asend()`` and ``asend_robust()`` when all receivers were asynchronous functions (:ticket:`35174`). + +* Fixed a regression in Django 5.0.1 where :meth:`.ModelAdmin.lookup_allowed` + would prevent filtering against foreign keys using lookups like ``__isnull`` + when the field was not included in :attr:`.ModelAdmin.list_filter` + (:ticket:`35173`). diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py index fad2dfaa1cd..de8d26ae465 100644 --- a/tests/modeladmin/tests.py +++ b/tests/modeladmin/tests.py @@ -174,7 +174,19 @@ class ModelAdminTests(TestCase): pass ma = PlaceAdmin(Place, self.site) - self.assertIs(ma.lookup_allowed("country", "1", request), True) + + cases = [ + ("country", "1"), + ("country__exact", "1"), + ("country__id", "1"), + ("country__id__exact", "1"), + ("country__isnull", True), + ("country__isnull", False), + ("country__id__isnull", False), + ] + for lookup, lookup_value in cases: + with self.subTest(lookup=lookup): + self.assertIs(ma.lookup_allowed(lookup, lookup_value, request), True) @isolate_apps("modeladmin") def test_lookup_allowed_non_autofield_primary_key(self):