1010from django .conf import settings
1111from django .core .exceptions import ImproperlyConfigured
1212from django .db import models
13+ from django .db .models .constants import LOOKUP_SEP
1314from django .template import loader
1415from django .utils import six
1516from django .utils .translation import ugettext_lazy as _
@@ -153,6 +154,25 @@ def construct_search(self, field_name):
153154 else :
154155 return "%s__icontains" % field_name
155156
157+ def must_call_distinct (self , opts , lookups ):
158+ """
159+ Return True if 'distinct()' should be used to query the given lookups.
160+ """
161+ for lookup in lookups :
162+ if lookup [0 ] in {'^' , '=' , '@' , '$' }:
163+ lookup = lookup [1 :]
164+ parts = lookup .split (LOOKUP_SEP )
165+ for part in parts :
166+ field = opts .get_field (part )
167+ if hasattr (field , 'get_path_info' ):
168+ # This field is a relation, update opts to follow the relation
169+ path_info = field .get_path_info ()
170+ opts = path_info [- 1 ].to_opts
171+ if any (path .m2m for path in path_info ):
172+ # This field is a m2m relation so we know we need to call distinct
173+ return True
174+ return False
175+
156176 def filter_queryset (self , request , queryset , view ):
157177 search_fields = getattr (view , 'search_fields' , None )
158178 search_terms = self .get_search_terms (request )
@@ -173,10 +193,12 @@ def filter_queryset(self, request, queryset, view):
173193 ]
174194 queryset = queryset .filter (reduce (operator .or_ , queries ))
175195
176- # Filtering against a many-to-many field requires us to
177- # call queryset.distinct() in order to avoid duplicate items
178- # in the resulting queryset.
179- return distinct (queryset , base )
196+ if self .must_call_distinct (queryset .model ._meta , search_fields ):
197+ # Filtering against a many-to-many field requires us to
198+ # call queryset.distinct() in order to avoid duplicate items
199+ # in the resulting queryset.
200+ queryset = distinct (queryset , base )
201+ return queryset
180202
181203 def to_html (self , request , queryset , view ):
182204 if not getattr (view , 'search_fields' , None ):
0 commit comments