From 594fcc2b7427f7baf2cf1a2d7cd2be61467df0c3 Mon Sep 17 00:00:00 2001 From: sarahboyce Date: Thu, 13 Apr 2023 11:46:47 +0200 Subject: Fixed #22569 -- Made ModelAdmin.lookup_allowed() respect get_list_filter(). Thank you Simon Meers for the initial patch. --- django/contrib/admin/options.py | 11 +++++++++-- django/contrib/admin/views/main.py | 15 ++++++++++++++- django/contrib/auth/admin.py | 6 ++++-- 3 files changed, 27 insertions(+), 5 deletions(-) (limited to 'django') diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 49c816dc9e..b0635669e9 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -436,7 +436,9 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): else self.get_list_display(request) ) - def lookup_allowed(self, lookup, value): + # RemovedInDjango60Warning: when the deprecation ends, replace with: + # def lookup_allowed(self, lookup, value, request): + def lookup_allowed(self, lookup, value, request=None): from django.contrib.admin.filters import SimpleListFilter model = self.model @@ -482,7 +484,12 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass): # Either a local field filter, or no fields at all. return True valid_lookups = {self.date_hierarchy} - for filter_item in self.list_filter: + # RemovedInDjango60Warning: when the deprecation ends, replace with: + # for filter_item in self.get_list_filter(request): + list_filter = ( + self.get_list_filter(request) if request is not None else self.list_filter + ) + for filter_item in list_filter: if isinstance(filter_item, type) and issubclass( filter_item, SimpleListFilter ): diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 9a130ae8a7..c99972c2bd 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -1,3 +1,4 @@ +import warnings from datetime import datetime, timedelta from django import forms @@ -31,7 +32,9 @@ from django.core.paginator import InvalidPage from django.db.models import Exists, F, Field, ManyToOneRel, OrderBy, OuterRef from django.db.models.expressions import Combinable from django.urls import reverse +from django.utils.deprecation import RemovedInDjango60Warning from django.utils.http import urlencode +from django.utils.inspect import func_supports_parameter from django.utils.timezone import make_aware from django.utils.translation import gettext @@ -174,9 +177,19 @@ class ChangeList: may_have_duplicates = False has_active_filters = False + supports_request = func_supports_parameter( + self.model_admin.lookup_allowed, "request" + ) + if not supports_request: + warnings.warn( + f"`request` must be added to the signature of " + f"{self.model_admin.__class__.__qualname__}.lookup_allowed().", + RemovedInDjango60Warning, + ) for key, value_list in lookup_params.items(): for value in value_list: - if not self.model_admin.lookup_allowed(key, value): + params = (key, value, request) if supports_request else (key, value) + if not self.model_admin.lookup_allowed(*params): raise DisallowedModelAdminLookup(f"Filtering by {key} not allowed") filter_specs = [] diff --git a/django/contrib/auth/admin.py b/django/contrib/auth/admin.py index 5424711643..f9532abc14 100644 --- a/django/contrib/auth/admin.py +++ b/django/contrib/auth/admin.py @@ -106,10 +106,12 @@ class UserAdmin(admin.ModelAdmin): ), ] + super().get_urls() - def lookup_allowed(self, lookup, value): + # RemovedInDjango60Warning: when the deprecation ends, replace with: + # def lookup_allowed(self, lookup, value, request): + def lookup_allowed(self, lookup, value, request=None): # Don't allow lookups involving passwords. return not lookup.startswith("password") and super().lookup_allowed( - lookup, value + lookup, value, request ) @sensitive_post_parameters_m -- cgit v1.2.1