diff --git a/wagtail/wagtailsearch/backends/db.py b/wagtail/wagtailsearch/backends/db.py index d190e29e8..cbde8d58f 100644 --- a/wagtail/wagtailsearch/backends/db.py +++ b/wagtail/wagtailsearch/backends/db.py @@ -1,6 +1,57 @@ from django.db import models -from wagtail.wagtailsearch.backends.base import BaseSearch +from wagtail.wagtailsearch.backends.base import BaseSearch, BaseSearchResults + + +class DBSearchQuery(object): + def __init__(self, queryset, query_string, fields=None): + self.queryset = queryset + self.query_string = query_string + self.fields = fields + + def get_queryset(self): + queryset = self.queryset + model = queryset.model + + if self.query_string is not None: + # Get fields + fields = self.fields or [field.field_name for field in model.get_searchable_search_fields()] + + # Get terms + terms = self.query_string.split() + if not terms: + return model.objects.none() + + # Filter by terms + for term in terms: + term_query = models.Q() + for field_name in fields: + # Check if the field exists (this will filter out indexed callables) + try: + model._meta.get_field_by_name(field_name) + except: + continue + + # Filter on this field + term_query |= models.Q(**{'%s__icontains' % field_name: term}) + + queryset = queryset.filter(term_query) + + # Distinct + queryset = queryset.distinct() + + return queryset + + +class DBSearchResults(BaseSearchResults): + def get_queryset(self): + return self.query.get_queryset()[self.start:self.stop] + + def _do_search(self): + return self.get_queryset() + + def _do_count(self): + return self.get_queryset().count() class DBSearch(BaseSearch): @@ -20,38 +71,10 @@ class DBSearch(BaseSearch): pass # Not needed def add_bulk(self, model, obj_list): - pass # Not needed + return # Not needed def delete(self, obj): pass # Not needed def _search(self, queryset, query_string, fields=None): - if query_string is not None: - # Get fields - if fields is None: - fields = [field.field_name for field in queryset.model.get_searchable_search_fields()] - - # Get terms - terms = query_string.split() - if not terms: - return queryset.model.objects.none() - - # Filter by terms - for term in terms: - term_query = models.Q() - for field_name in fields: - # Check if the field exists (this will filter out indexed callables) - try: - queryset.model._meta.get_field_by_name(field_name) - except: - continue - - # Filter on this field - term_query |= models.Q(**{'%s__icontains' % field_name: term}) - - queryset = queryset.filter(term_query) - - # Distinct - queryset = queryset.distinct() - - return queryset + return DBSearchResults(self, DBSearchQuery(queryset, query_string, fields=fields))