I have implemented search in my Django application to allow searching by more than one field. This results in Django always using a LEFT OUTER JOIN, which in my case generates the wrong results. However, when I change the SQL generated from a LEFT OUTER JOIN to an INNER JOIN, it returns the correct result.
I am thinking it has to do with the way Q object in my code below. from django.db import models, transaction...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 class CoreSearchMixin(object): """Subclasses must define search_fields = [field_1, ...field_n] where the field is a string, the name of a field, and can contain the following prefix characters: '^': the search field must start with the search term, case insensitive '=': the search field must exactly equal the search term, case insensitive '@': full-text search If no prefix is given, any string that contains the search field will match. """ search_fields = None search_form_class = SearchForm @cachedproperty def search_form(self): return self.search_form_class(getattr(self.request, self.request.method)) def get_query_help_message(self): """Returns a comma separated list of fields that are used in the search, to help the user create a search. """ fields = [] if self.search_fields: for search_field in self.search_fields: field = get_field_from_path(self.model, search_field) fields.append(field.verbose_name.title()) return ",".join(fields) def get_filtered_queryset(self, queryset): if self.search_form.is_valid(): self.query = self.search_form.cleaned_data['q'] else: self.query = None if self.search_fields and self.query: orm_lookups = (construct_search(str(search_field).replace('.', '__')) for search_field in self.search_fields) chained_or_queries = None for bit in self.query.split(): or_queries = (models.Q(**{orm_lookup: bit}) for orm_lookup in orm_lookups) if chained_or_queries: chained_or_queries = itertools.chain(chained_or_queries, or_queries) else: chained_or_queries = or_queries return queryset.filter(reduce(operator.or_, chained_or_queries)) else: return queryset def get_context_data(self, **kwargs): return super(CoreSearchMixin, self).get_context_data( search_form=self.search_form, query_help_message=self.get_query_help_message(), search_fields=self.search_fields, **kwargs ) How can I ensure that an INNER JOIN is used instead of a LEFT OUTER JOIN in the case of my code above? http://stackoverflow.com/questions/24927062/forcing-django-to-use-inner-join-instead-of-left-outer-join -- You received this message because you are subscribed to the Google Groups "Django users" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-users+unsubscr...@googlegroups.com. To post to this group, send email to django-users@googlegroups.com. Visit this group at http://groups.google.com/group/django-users. To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/CAEAUGdVL7sJQsmh8WEC%3Dp031dL%3D-YF8mg5c_kvFyjCSAPwVxNA%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.