Refs #1873 -- Used GET.lists() in admin filters.

This commit is contained in:
sarahboyce 2023-03-06 14:59:20 +01:00 committed by Mariusz Felisiak
parent 8d6f959be2
commit d03dc63177
3 changed files with 35 additions and 18 deletions

View File

@ -9,6 +9,7 @@ import datetime
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.utils import (
get_last_value_from_parameters,
get_model_from_relation,
prepare_lookup_value,
reverse_field_path,
@ -98,7 +99,7 @@ class SimpleListFilter(FacetsMixin, ListFilter):
)
if self.parameter_name in params:
value = params.pop(self.parameter_name)
self.used_parameters[self.parameter_name] = value
self.used_parameters[self.parameter_name] = value[-1]
lookup_choices = self.lookups(request, model_admin)
if lookup_choices is None:
lookup_choices = ()
@ -219,8 +220,10 @@ class RelatedFieldListFilter(FieldListFilter):
other_model = get_model_from_relation(field)
self.lookup_kwarg = "%s__%s__exact" % (field_path, field.target_field.name)
self.lookup_kwarg_isnull = "%s__isnull" % field_path
self.lookup_val = params.get(self.lookup_kwarg)
self.lookup_val_isnull = params.get(self.lookup_kwarg_isnull)
self.lookup_val = get_last_value_from_parameters(params, self.lookup_kwarg)
self.lookup_val_isnull = get_last_value_from_parameters(
params, self.lookup_kwarg_isnull
)
super().__init__(field, request, params, model, model_admin, field_path)
self.lookup_choices = self.field_choices(field, request, model_admin)
if hasattr(field, "verbose_name"):
@ -317,8 +320,8 @@ class BooleanFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = "%s__exact" % field_path
self.lookup_kwarg2 = "%s__isnull" % field_path
self.lookup_val = params.get(self.lookup_kwarg)
self.lookup_val2 = params.get(self.lookup_kwarg2)
self.lookup_val = get_last_value_from_parameters(params, self.lookup_kwarg)
self.lookup_val2 = get_last_value_from_parameters(params, self.lookup_kwarg2)
super().__init__(field, request, params, model, model_admin, field_path)
if (
self.used_parameters
@ -388,8 +391,10 @@ class ChoicesFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = "%s__exact" % field_path
self.lookup_kwarg_isnull = "%s__isnull" % field_path
self.lookup_val = params.get(self.lookup_kwarg)
self.lookup_val_isnull = params.get(self.lookup_kwarg_isnull)
self.lookup_val = get_last_value_from_parameters(params, self.lookup_kwarg)
self.lookup_val_isnull = get_last_value_from_parameters(
params, self.lookup_kwarg_isnull
)
super().__init__(field, request, params, model, model_admin, field_path)
def expected_parameters(self):
@ -450,7 +455,7 @@ class DateFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.field_generic = "%s__" % field_path
self.date_params = {
k: v for k, v in params.items() if k.startswith(self.field_generic)
k: v[-1] for k, v in params.items() if k.startswith(self.field_generic)
}
now = timezone.now()
@ -550,8 +555,10 @@ class AllValuesFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = field_path
self.lookup_kwarg_isnull = "%s__isnull" % field_path
self.lookup_val = params.get(self.lookup_kwarg)
self.lookup_val_isnull = params.get(self.lookup_kwarg_isnull)
self.lookup_val = get_last_value_from_parameters(params, self.lookup_kwarg)
self.lookup_val_isnull = get_last_value_from_parameters(
params, self.lookup_kwarg_isnull
)
self.empty_value_display = model_admin.get_empty_value_display()
parent_model, reverse_path = reverse_field_path(model, field_path)
# Obey parent ModelAdmin queryset when deciding which options to show
@ -646,7 +653,7 @@ class EmptyFieldListFilter(FieldListFilter):
)
)
self.lookup_kwarg = "%s__isempty" % field_path
self.lookup_val = params.get(self.lookup_kwarg)
self.lookup_val = get_last_value_from_parameters(params, self.lookup_kwarg)
super().__init__(field, request, params, model, model_admin, field_path)
def get_lookup_condition(self):

View File

@ -54,10 +54,17 @@ def lookup_spawns_duplicates(opts, lookup_path):
return False
def get_last_value_from_parameters(parameters, key):
value = parameters.get(key)
return value[-1] if isinstance(value, list) else value
def prepare_lookup_value(key, value, separator=","):
"""
Return a lookup value prepared to be used in queryset filtering.
"""
if isinstance(value, list):
value = value[-1]
# if key ends with __in, split parameter into separate values
if key.endswith("__in"):
value = value.split(separator)

View File

@ -123,10 +123,13 @@ class ChangeList:
)
self.to_field = to_field
self.params = dict(request.GET.items())
self.filter_params = dict(request.GET.lists())
if PAGE_VAR in self.params:
del self.params[PAGE_VAR]
del self.filter_params[PAGE_VAR]
if ERROR_FLAG in self.params:
del self.params[ERROR_FLAG]
del self.filter_params[ERROR_FLAG]
self.remove_facet_link = self.get_query_string(remove=[IS_FACETS_VAR])
self.add_facet_link = self.get_query_string({IS_FACETS_VAR: True})
@ -156,7 +159,7 @@ class ChangeList:
"""
Return all params except IGNORED_PARAMS.
"""
params = params or self.params
params = params or self.filter_params
lookup_params = params.copy() # a dictionary of the query string
# Remove all the parameters that are globally and systematically
# ignored.
@ -171,7 +174,7 @@ class ChangeList:
has_active_filters = False
for key, value in lookup_params.items():
if not self.model_admin.lookup_allowed(key, value):
if not self.model_admin.lookup_allowed(key, value[-1]):
raise DisallowedModelAdminLookup("Filtering by %s not allowed" % key)
filter_specs = []
@ -224,9 +227,9 @@ class ChangeList:
day = lookup_params.pop("%s__day" % self.date_hierarchy, None)
try:
from_date = datetime(
int(year),
int(month if month is not None else 1),
int(day if day is not None else 1),
int(year[-1]),
int(month[-1] if month is not None else 1),
int(day[-1] if day is not None else 1),
)
except ValueError as e:
raise IncorrectLookupParameters(e) from e
@ -273,7 +276,7 @@ class ChangeList:
new_params = {}
if remove is None:
remove = []
p = self.params.copy()
p = self.filter_params.copy()
for r in remove:
for k in list(p):
if k.startswith(r):
@ -284,7 +287,7 @@ class ChangeList:
del p[k]
else:
p[k] = v
return "?%s" % urlencode(sorted(p.items()))
return "?%s" % urlencode(sorted(p.items()), doseq=True)
def get_results(self, request):
paginator = self.model_admin.get_paginator(