diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index a527e42c6d..0b79ac75ef 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -1019,7 +1019,7 @@ class ModelAdmin(BaseModelAdmin): # Otherwise, use the field with icontains. return "%s__icontains" % field_name - use_distinct = False + may_have_duplicates = False search_fields = self.get_search_fields(request) if search_fields and search_term: orm_lookups = [construct_search(str(search_field)) @@ -1030,9 +1030,11 @@ class ModelAdmin(BaseModelAdmin): or_queries = [models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups] queryset = queryset.filter(reduce(operator.or_, or_queries)) - use_distinct |= any(lookup_needs_distinct(self.opts, search_spec) for search_spec in orm_lookups) - - return queryset, use_distinct + may_have_duplicates |= any( + lookup_needs_distinct(self.opts, search_spec) + for search_spec in orm_lookups + ) + return queryset, may_have_duplicates def get_preserved_filters(self, request): """ diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index fefed29933..dc43e7849d 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -122,7 +122,7 @@ class ChangeList: def get_filters(self, request): lookup_params = self.get_filters_params() - use_distinct = False + may_have_duplicates = False has_active_filters = False for key, value in lookup_params.items(): @@ -157,7 +157,7 @@ class ChangeList: # processes. If that happened, check if distinct() is needed to # remove duplicate results. if lookup_params_count > len(lookup_params): - use_distinct = use_distinct or lookup_needs_distinct(self.lookup_opts, field_path) + may_have_duplicates |= lookup_needs_distinct(self.lookup_opts, field_path) if spec and spec.has_output(): filter_specs.append(spec) if lookup_params_count > len(lookup_params): @@ -203,9 +203,9 @@ class ChangeList: try: for key, value in lookup_params.items(): lookup_params[key] = prepare_lookup_value(key, value) - use_distinct = use_distinct or lookup_needs_distinct(self.lookup_opts, key) + may_have_duplicates |= lookup_needs_distinct(self.lookup_opts, key) return ( - filter_specs, bool(filter_specs), lookup_params, use_distinct, + filter_specs, bool(filter_specs), lookup_params, may_have_duplicates, has_active_filters, ) except FieldDoesNotExist as e: @@ -445,7 +445,7 @@ class ChangeList: self.filter_specs, self.has_filters, remaining_lookup_params, - filters_use_distinct, + filters_may_have_duplicates, self.has_active_filters, ) = self.get_filters(request) # Then, we let every list filter modify the queryset to its liking. @@ -480,7 +480,9 @@ class ChangeList: qs = qs.order_by(*ordering) # Apply search results - qs, search_use_distinct = self.model_admin.get_search_results(request, qs, self.query) + qs, search_may_have_duplicates = self.model_admin.get_search_results( + request, qs, self.query, + ) # Set query string for clearing all filters. self.clear_all_filters_qs = self.get_query_string( @@ -488,7 +490,7 @@ class ChangeList: remove=self.get_filters_params(), ) # Remove duplicates from results, if necessary - if filters_use_distinct | search_use_distinct: + if filters_may_have_duplicates | search_may_have_duplicates: return qs.distinct() else: return qs diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt index 5b3493c858..8da7a72f10 100644 --- a/docs/ref/contrib/admin/index.txt +++ b/docs/ref/contrib/admin/index.txt @@ -1576,14 +1576,16 @@ templates used by the :class:`ModelAdmin` views: search_fields = ('name',) def get_search_results(self, request, queryset, search_term): - queryset, use_distinct = super().get_search_results(request, queryset, search_term) + queryset, may_have_duplicates = super().get_search_results( + request, queryset, search_term, + ) try: search_term_as_int = int(search_term) except ValueError: pass else: queryset |= self.model.objects.filter(age=search_term_as_int) - return queryset, use_distinct + return queryset, may_have_duplicates This implementation is more efficient than ``search_fields = ('name', '=age')`` which results in a string comparison for the numeric diff --git a/tests/admin_views/admin.py b/tests/admin_views/admin.py index 951d62d228..e2ecc9ed53 100644 --- a/tests/admin_views/admin.py +++ b/tests/admin_views/admin.py @@ -653,14 +653,16 @@ class PluggableSearchPersonAdmin(admin.ModelAdmin): search_fields = ('name',) def get_search_results(self, request, queryset, search_term): - queryset, use_distinct = super().get_search_results(request, queryset, search_term) + queryset, may_have_duplicates = super().get_search_results( + request, queryset, search_term, + ) try: search_term_as_int = int(search_term) except ValueError: pass else: queryset |= self.model.objects.filter(age=search_term_as_int) - return queryset, use_distinct + return queryset, may_have_duplicates class AlbumAdmin(admin.ModelAdmin):