summaryrefslogtreecommitdiff
path: root/django
diff options
context:
space:
mode:
Diffstat (limited to 'django')
-rw-r--r--django/contrib/admin/options.py31
-rw-r--r--django/contrib/admin/views/main.py32
2 files changed, 35 insertions, 28 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index e7edccd585..f27ed3b653 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -1,4 +1,5 @@
import copy
+import operator
from functools import update_wrapper, partial
from django import forms
@@ -9,7 +10,7 @@ from django.forms.models import (modelform_factory, modelformset_factory,
from django.contrib.contenttypes.models import ContentType
from django.contrib.admin import widgets, helpers
from django.contrib.admin.util import (unquote, flatten_fieldsets, get_deleted_objects,
- model_format_dict, NestedObjects)
+ model_format_dict, NestedObjects, lookup_needs_distinct)
from django.contrib.admin import validation
from django.contrib.admin.templatetags.admin_static import static
from django.contrib import messages
@@ -255,6 +256,34 @@ class BaseModelAdmin(six.with_metaclass(RenameBaseModelAdminMethods)):
"""
return self.prepopulated_fields
+ def get_search_results(self, request, queryset, search_term):
+ # Apply keyword searches.
+ def construct_search(field_name):
+ if field_name.startswith('^'):
+ return "%s__istartswith" % field_name[1:]
+ elif field_name.startswith('='):
+ return "%s__iexact" % field_name[1:]
+ elif field_name.startswith('@'):
+ return "%s__search" % field_name[1:]
+ else:
+ return "%s__icontains" % field_name
+
+ use_distinct = False
+ if self.search_fields and search_term:
+ orm_lookups = [construct_search(str(search_field))
+ for search_field in self.search_fields]
+ for bit in search_term.split():
+ or_queries = [models.Q(**{orm_lookup: bit})
+ for orm_lookup in orm_lookups]
+ queryset = queryset.filter(reduce(operator.or_, or_queries))
+ if not use_distinct:
+ for search_spec in orm_lookups:
+ if lookup_needs_distinct(self.opts, search_spec):
+ use_distinct = True
+ break
+
+ return queryset, use_distinct
+
def get_queryset(self, request):
"""
Returns a QuerySet of all model instances that can be edited by the
diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py
index 050d4776d0..21ac30b7b3 100644
--- a/django/contrib/admin/views/main.py
+++ b/django/contrib/admin/views/main.py
@@ -1,7 +1,5 @@
-import operator
import sys
import warnings
-from functools import reduce
from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
from django.core.paginator import InvalidPage
@@ -331,7 +329,7 @@ class ChangeList(six.with_metaclass(RenameChangeListMethods)):
def get_queryset(self, request):
# First, we collect all the declared list filters.
(self.filter_specs, self.has_filters, remaining_lookup_params,
- use_distinct) = self.get_filters(request)
+ filters_use_distinct) = self.get_filters(request)
# Then, we let every list filter modify the queryset to its liking.
qs = self.root_queryset
@@ -378,31 +376,11 @@ class ChangeList(six.with_metaclass(RenameChangeListMethods)):
ordering = self.get_ordering(request, qs)
qs = qs.order_by(*ordering)
- # Apply keyword searches.
- def construct_search(field_name):
- if field_name.startswith('^'):
- return "%s__istartswith" % field_name[1:]
- elif field_name.startswith('='):
- return "%s__iexact" % field_name[1:]
- elif field_name.startswith('@'):
- return "%s__search" % field_name[1:]
- else:
- return "%s__icontains" % field_name
-
- if self.search_fields and self.query:
- orm_lookups = [construct_search(str(search_field))
- for search_field in self.search_fields]
- for bit in self.query.split():
- or_queries = [models.Q(**{orm_lookup: bit})
- for orm_lookup in orm_lookups]
- qs = qs.filter(reduce(operator.or_, or_queries))
- if not use_distinct:
- for search_spec in orm_lookups:
- if lookup_needs_distinct(self.lookup_opts, search_spec):
- use_distinct = True
- break
+ # Apply search results
+ qs, search_use_distinct = self.model_admin.get_search_results(request, qs, self.query)
- if use_distinct:
+ # Remove duplicates from results, if neccesary
+ if filters_use_distinct | search_use_distinct:
return qs.distinct()
else:
return qs