From 08ced063ff09d102922deaf279275e4c0fb5ff4d Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Sun, 22 Jun 2014 18:56:08 +0100 Subject: [PATCH] Moved search method into base search backend --- wagtail/wagtailcore/models.py | 2 +- wagtail/wagtailsearch/backends/base.py | 38 ++++++++++++++++++- wagtail/wagtailsearch/backends/db.py | 34 +++++------------ .../wagtailsearch/backends/elasticsearch.py | 34 +---------------- 4 files changed, 48 insertions(+), 60 deletions(-) diff --git a/wagtail/wagtailcore/models.py b/wagtail/wagtailcore/models.py index 4964966a3..b6a664548 100644 --- a/wagtail/wagtailcore/models.py +++ b/wagtail/wagtailcore/models.py @@ -514,7 +514,7 @@ class Page(six.with_metaclass(PageBase, MP_Node, ClusterableModel, indexed.Index # Search s = get_search_backend() - return s.search(query_string, model=cls, fields=fields, filters=filters, prefetch_related=prefetch_related) + return s.search(query_string, cls, fields=fields, filters=filters, prefetch_related=prefetch_related) @classmethod def clean_subpage_types(cls): diff --git a/wagtail/wagtailsearch/backends/base.py b/wagtail/wagtailsearch/backends/base.py index 393ecae1b..82e2e8d56 100644 --- a/wagtail/wagtailsearch/backends/base.py +++ b/wagtail/wagtailsearch/backends/base.py @@ -1,6 +1,9 @@ from django.db import models +from django.db.models.query import QuerySet +from django.core.exceptions import ImproperlyConfigured from wagtail.wagtailsearch.indexed import Indexed +from wagtail.wagtailsearch.utils import normalise_query_string class BaseSearch(object): @@ -32,5 +35,38 @@ class BaseSearch(object): def delete(self, obj): return NotImplemented - def search(self, query_string, model, fields=None, filters={}, prefetch_related=[]): + def _search(self, queryset, query_string, fields=None): return NotImplemented + + def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None): + # Find model/queryset + if isinstance(model_or_queryset, QuerySet): + model = model_or_queryset.model + queryset = model_or_queryset + else: + model = model_or_queryset + queryset = model_or_queryset.objects.all() + + # Model must be a descendant of Indexed and be a django model + if not issubclass(model, Indexed) or not issubclass(model, models.Model): + return [] + + # Normalise query string + if query_string is not None: + query_string = normalise_query_string(query_string) + + # Check that theres still a query string after the clean up + if query_string == "": + return [] + + # Apply filters to queryset + if filters: + queryset = queryset.filter(**filters) + + # Prefetch related + if prefetch_related: + for prefetch in prefetch_related: + queryset = queryset.prefetch_related(prefetch) + + # Search + return self._search(queryset, query_string, fields=fields) diff --git a/wagtail/wagtailsearch/backends/db.py b/wagtail/wagtailsearch/backends/db.py index 56536e343..a94fe3c58 100644 --- a/wagtail/wagtailsearch/backends/db.py +++ b/wagtail/wagtailsearch/backends/db.py @@ -2,7 +2,6 @@ from django.db import models from wagtail.wagtailsearch.backends.base import BaseSearch from wagtail.wagtailsearch.indexed import Indexed -from wagtail.wagtailsearch.utils import normalise_query_string class DBSearch(BaseSearch): @@ -27,26 +26,16 @@ class DBSearch(BaseSearch): def delete(self, obj): pass # Not needed - def search(self, query_string, model, fields=None, filters=None, prefetch_related=None): - # Get fields - if fields is None: - fields = [field.field_name for field in model.get_searchable_search_fields()] - - # Start with all objects - query = model.objects.all() - - # Apply filters - if filters: - query = query.filter(**filters) - + def _search(self, queryset, query_string, fields=None): if query_string is not None: - # Normalise query string - query_string = normalise_query_string(query_string) + # 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 model.objects.none() + return queryset.model.objects.none() # Filter by terms for term in terms: @@ -54,21 +43,16 @@ class DBSearch(BaseSearch): 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) + queryset.model._meta.get_field_by_name(field_name) except: continue # Filter on this field term_query |= models.Q(**{'%s__icontains' % field_name: term}) - query = query.filter(term_query) + queryset = queryset.filter(term_query) # Distinct - query = query.distinct() + queryset = queryset.distinct() - # Prefetch related - if prefetch_related: - for prefetch in prefetch_related: - query = query.prefetch_related(prefetch) - - return query + return queryset diff --git a/wagtail/wagtailsearch/backends/elasticsearch.py b/wagtail/wagtailsearch/backends/elasticsearch.py index ea0413eed..8f17ba6ce 100644 --- a/wagtail/wagtailsearch/backends/elasticsearch.py +++ b/wagtail/wagtailsearch/backends/elasticsearch.py @@ -3,14 +3,12 @@ from __future__ import absolute_import import json from django.db import models -from django.db.models.query import QuerySet from elasticsearch import Elasticsearch, NotFoundError, RequestError from elasticsearch.helpers import bulk from wagtail.wagtailsearch.backends.base import BaseSearch from wagtail.wagtailsearch.indexed import Indexed, SearchField, FilterField -from wagtail.wagtailsearch.utils import normalise_query_string class ElasticSearchMapping(object): @@ -576,35 +574,5 @@ class ElasticSearch(BaseSearch): except NotFoundError: pass # Document doesn't exist, ignore this exception - def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None): - # Find model/queryset - if isinstance(model_or_queryset, QuerySet): - model = model_or_queryset.model - queryset = model_or_queryset - else: - model = model_or_queryset - queryset = model_or_queryset.objects.all() - - # Model must be a descendant of Indexed and be a django model - if not issubclass(model, Indexed) or not issubclass(model, models.Model): - return [] - - # Normalise query string - if query_string is not None: - query_string = normalise_query_string(query_string) - - # Check that theres still a query string after the clean up - if query_string == "": - return [] - - # Apply filters to queryset - if filters: - queryset = queryset.filter(**filters) - - # Prefetch related - if prefetch_related: - for prefetch in prefetch_related: - queryset = queryset.prefetch_related(prefetch) - - # Return search results + def _search(self, queryset, query_string, fields=None): return ElasticSearchResults(self, ElasticSearchQuery(queryset, query_string, fields=fields))