diff --git a/django/contrib/admin/filters.py b/django/contrib/admin/filters.py index 9e468dedd9..3ae7805dc2 100644 --- a/django/contrib/admin/filters.py +++ b/django/contrib/admin/filters.py @@ -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): diff --git a/django/contrib/admin/utils.py b/django/contrib/admin/utils.py index b971bd528f..90442788c9 100644 --- a/django/contrib/admin/utils.py +++ b/django/contrib/admin/utils.py @@ -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) diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 6d88dfc883..c0c03819f3 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -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(