Merge branch 'kaedroho-search-ordering'

pull/1822/head
Matt Westcott 2015-10-13 15:27:32 +01:00
commit 928bc0d25f
13 zmienionych plików z 304 dodań i 65 usunięć

Wyświetl plik

@ -138,7 +138,6 @@ Here's an example of using the "operator" keyword argument:
# Only "hello world" returned as that's the only item that contains both terms
[<Thing: Hello world>]
For page, image and document models, the ``operator`` keyword argument is also supported on the QuerySet's ``search`` method:
.. code-block:: python
@ -149,6 +148,24 @@ For page, image and document models, the ``operator`` keyword argument is also s
[<Page: Hello World>, <Page: Hello>, <Page: World>]
Custom ordering
^^^^^^^^^^^^^^^
.. versionadded:: 1.2
By default, search results are ordered by relevance, if the backend supports it. To preserve the QuerySet's existing ordering, the ``order_by_relevance`` keyword argument needs to be set to ``False`` on the ``search()`` method.
For example:
.. code-block:: python
# Get a list of events ordered by date
>>> EventPage.objects.order_by('date').search("Event", order_by_relevance=False)
# Events ordered by date
[<EventPage: Easter>, <EventPage: Halloween>, <EventPage: Christmas>]
.. _wagtailsearch_frontend_views:

Wyświetl plik

@ -43,6 +43,9 @@ class SearchTest(models.Model, index.Indexed):
# Return the child if there is one, otherwise return self
return child or self
def __str__(self):
return self.title
class SearchTestChild(SearchTest):
subtitle = models.CharField(max_length=255, null=True, blank=True)

Wyświetl plik

@ -235,8 +235,10 @@ class PageManager(models.Manager):
def not_public(self):
return self.get_queryset().not_public()
def search(self, query_string, fields=None, backend='default'):
return self.get_queryset().search(query_string, fields=fields, backend=backend)
def search(self, query_string, fields=None,
operator=None, order_by_relevance=True, backend='default'):
return self.get_queryset().search(query_string, fields=fields,
operator=operator, order_by_relevance=order_by_relevance, backend=backend)
def specific(self):
return self.get_queryset().specific()

Wyświetl plik

@ -7,10 +7,10 @@ from django.apps import apps
from treebeard.mp_tree import MP_NodeQuerySet
from wagtail.wagtailsearch.backends import get_search_backend
from wagtail.wagtailsearch.queryset import SearchableQuerySetMixin
class PageQuerySet(MP_NodeQuerySet):
class PageQuerySet(SearchableQuerySetMixin, MP_NodeQuerySet):
def live_q(self):
return Q(live=True)
@ -197,13 +197,6 @@ class PageQuerySet(MP_NodeQuerySet):
"""
return self.exclude(self.public_q())
def search(self, query_string, fields=None, operator=None, backend='default'):
"""
This runs a search query on all the pages in the QuerySet
"""
search_backend = get_search_backend(backend)
return search_backend.search(query_string, self, fields=fields, operator=operator)
def unpublish(self):
"""
This unpublishes all pages in the QuerySet

Wyświetl plik

@ -322,6 +322,46 @@ class TestPageQuerySet(TestCase):
self.assertTrue(pages.filter(id=event.id).exists())
class TestPageQuerySetSearch(TestCase):
fixtures = ['test.json']
def test_search(self):
pages = EventPage.objects.search('moon', fields=['location'])
self.assertEqual(pages.count(), 2)
self.assertIn(Page.objects.get(url_path='/home/events/tentative-unpublished-event/').specific, pages)
self.assertIn(Page.objects.get(url_path='/home/events/someone-elses-event/').specific, pages)
def test_operators(self):
results = EventPage.objects.search("moon ponies", operator='and')
self.assertEqual(list(results), [
Page.objects.get(url_path='/home/events/tentative-unpublished-event/').specific
])
results = EventPage.objects.search("moon ponies", operator='or')
sorted_results = sorted(results, key=lambda page: page.url_path)
self.assertEqual(sorted_results, [
Page.objects.get(url_path='/home/events/someone-elses-event/').specific,
Page.objects.get(url_path='/home/events/tentative-unpublished-event/').specific,
])
def test_custom_order(self):
pages = EventPage.objects.order_by('url_path').search('moon', fields=['location'], order_by_relevance=False)
self.assertEqual(list(pages), [
Page.objects.get(url_path='/home/events/someone-elses-event/').specific,
Page.objects.get(url_path='/home/events/tentative-unpublished-event/').specific,
])
pages = EventPage.objects.order_by('-url_path').search('moon', fields=['location'], order_by_relevance=False)
self.assertEqual(list(pages), [
Page.objects.get(url_path='/home/events/tentative-unpublished-event/').specific,
Page.objects.get(url_path='/home/events/someone-elses-event/').specific,
])
class TestSpecificQuery(TestCase):
"""
Test the .specific() queryset method. This is isolated in its own test case

Wyświetl plik

@ -16,16 +16,11 @@ from django.utils.encoding import python_2_unicode_compatible
from wagtail.wagtailadmin.taggable import TagSearchable
from wagtail.wagtailadmin.utils import get_object_usage
from wagtail.wagtailsearch import index
from wagtail.wagtailsearch.backends import get_search_backend
from wagtail.wagtailsearch.queryset import SearchableQuerySetMixin
class DocumentQuerySet(models.QuerySet):
def search(self, query_string, fields=None, operator=None, backend='default'):
"""
This runs a search query on all the documents in the QuerySet
"""
search_backend = get_search_backend(backend)
return search_backend.search(query_string, self, fields=fields, operator=operator)
class DocumentQuerySet(SearchableQuerySetMixin, models.QuerySet):
pass
@python_2_unicode_compatible

Wyświetl plik

@ -34,6 +34,26 @@ class TestDocumentQuerySet(TestCase):
results = models.Document.objects.search("Test")
self.assertEqual(list(results), [document])
def test_operators(self):
aaa_document = models.Document.objects.create(title="AAA Test document")
zzz_document = models.Document.objects.create(title="ZZZ Test document")
results = models.Document.objects.search("aaa test", operator='and')
self.assertEqual(list(results), [aaa_document])
results = models.Document.objects.search("aaa test", operator='or')
sorted_results = sorted(results, key=lambda doc: doc.title)
self.assertEqual(sorted_results, [aaa_document, zzz_document])
def test_custom_ordering(self):
aaa_document = models.Document.objects.create(title="AAA Test document")
zzz_document = models.Document.objects.create(title="ZZZ Test document")
results = models.Document.objects.order_by('title').search("Test")
self.assertEqual(list(results), [aaa_document, zzz_document])
results = models.Document.objects.order_by('-title').search("Test")
self.assertEqual(list(results), [zzz_document, aaa_document])
class TestDocumentPermissions(TestCase):
def setUp(self):

Wyświetl plik

@ -28,7 +28,7 @@ from unidecode import unidecode
from wagtail.wagtailcore import hooks
from wagtail.wagtailadmin.taggable import TagSearchable
from wagtail.wagtailsearch import index
from wagtail.wagtailsearch.backends import get_search_backend
from wagtail.wagtailsearch.queryset import SearchableQuerySetMixin
from wagtail.wagtailimages.rect import Rect
from wagtail.wagtailimages.exceptions import InvalidFilterSpecError
from wagtail.wagtailadmin.utils import get_object_usage
@ -42,13 +42,8 @@ class SourceImageIOError(IOError):
pass
class ImageQuerySet(models.QuerySet):
def search(self, query_string, fields=None, operator=None, backend='default'):
"""
This runs a search query on all the images in the QuerySet
"""
search_backend = get_search_backend(backend)
return search_backend.search(query_string, self, fields=fields, operator=operator)
class ImageQuerySet(SearchableQuerySetMixin, models.QuerySet):
pass
def get_upload_to(instance, filename):

Wyświetl plik

@ -99,6 +99,38 @@ class TestImageQuerySet(TestCase):
results = Image.objects.search("Test")
self.assertEqual(list(results), [image])
def test_operators(self):
aaa_image = Image.objects.create(
title="AAA Test image",
file=get_test_image_file(),
)
zzz_image = Image.objects.create(
title="ZZZ Test image",
file=get_test_image_file(),
)
results = Image.objects.search("aaa test", operator='and')
self.assertEqual(list(results), [aaa_image])
results = Image.objects.search("aaa test", operator='or')
sorted_results = sorted(results, key=lambda img: img.title)
self.assertEqual(sorted_results, [aaa_image, zzz_image])
def test_custom_ordering(self):
aaa_image = Image.objects.create(
title="AAA Test image",
file=get_test_image_file(),
)
zzz_image = Image.objects.create(
title="ZZZ Test image",
file=get_test_image_file(),
)
results = Image.objects.order_by('title').search("Test")
self.assertEqual(list(results), [aaa_image, zzz_image])
results = Image.objects.order_by('-title').search("Test")
self.assertEqual(list(results), [zzz_image, aaa_image])
class TestImagePermissions(TestCase):
def setUp(self):

Wyświetl plik

@ -18,11 +18,12 @@ class FieldError(Exception):
class BaseSearchQuery(object):
DEFAULT_OPERATOR = 'or'
def __init__(self, queryset, query_string, fields=None, operator=None):
def __init__(self, queryset, query_string, fields=None, operator=None, order_by_relevance=True):
self.queryset = queryset
self.query_string = query_string
self.fields = fields
self.operator = operator or self.DEFAULT_OPERATOR
self.order_by_relevance = order_by_relevance
def _get_searchable_field(self, field_attname):
# Get field
@ -203,7 +204,7 @@ class BaseSearch(object):
def delete(self, obj):
raise NotImplementedError
def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None, operator=None):
def search(self, query_string, model_or_queryset, fields=None, filters=None, prefetch_related=None, operator=None, order_by_relevance=True):
# Find model/queryset
if isinstance(model_or_queryset, QuerySet):
model = model_or_queryset.model
@ -236,5 +237,5 @@ class BaseSearch(object):
raise ValueError("operator must be either 'or' or 'and'")
# Search
search_query = self.search_query_class(queryset, query_string, fields=fields, operator=operator)
search_query = self.search_query_class(queryset, query_string, fields=fields, operator=operator, order_by_relevance=order_by_relevance)
return self.search_results_class(self, search_query)

Wyświetl plik

@ -1,6 +1,8 @@
from __future__ import absolute_import
import json
import six
import warnings
from django.utils.six.moves.urllib.parse import urlparse
@ -11,6 +13,7 @@ from django.utils.crypto import get_random_string
from wagtail.wagtailsearch.backends.base import BaseSearch, BaseSearchQuery, BaseSearchResults
from wagtail.wagtailsearch.index import SearchField, FilterField, class_is_indexed
from wagtail.utils.deprecation import RemovedInWagtail14Warning
INDEX_SETTINGS = {
@ -245,8 +248,7 @@ class ElasticSearchQuery(BaseSearchQuery):
return filter_out
def to_es(self):
# Query
def get_inner_query(self):
if self.query_string is not None:
fields = self.fields or ['_all', '_partials']
@ -274,7 +276,9 @@ class ElasticSearchQuery(BaseSearchQuery):
'match_all': {}
}
# Filters
return query
def get_filters(self):
filters = []
# Filter by content type
@ -289,35 +293,106 @@ class ElasticSearchQuery(BaseSearchQuery):
if queryset_filters:
filters.append(queryset_filters)
return filters
def get_query(self):
inner_query = self.get_inner_query()
filters = self.get_filters()
if len(filters) == 1:
query = {
return {
'filtered': {
'query': query,
'query': inner_query,
'filter': filters[0],
}
}
elif len(filters) > 1:
query = {
return {
'filtered': {
'query': query,
'query': inner_query,
'filter': {
'and': filters,
}
}
}
else:
return inner_query
return query
def get_sort(self):
# Ordering by relevance is the default in Elasticsearch
if self.order_by_relevance:
return
# Get queryset and make sure its ordered
if self.queryset.ordered:
order_by_fields = self.queryset.query.order_by
sort = []
for order_by_field in order_by_fields:
reverse = False
field_name = order_by_field
if order_by_field.startswith('-'):
reverse = True
field_name = order_by_field[1:]
field = self._get_filterable_field(field_name)
field_index_name = field.get_index_name(self.queryset.model)
sort.append({
field_index_name: 'desc' if reverse else 'asc'
})
return sort
else:
# Order by pk field
return ['pk']
def __repr__(self):
return json.dumps(self.to_es())
return json.dumps(self.get_query())
def to_es(self):
warnings.warn(
"The ElasticSearchQuery.to_es() method is deprecated. "
"Please use the ElasticSearchQuery.get_query() method instead.",
RemovedInWagtail14Warning, stacklevel=2)
return self.get_query()
class ElasticSearchResults(BaseSearchResults):
def _get_es_body(self, for_count=False):
# If to_es has been overridden, call it and raise a deprecation warning
if isinstance(self.query, ElasticSearchQuery) and six.get_method_function(self.query.to_es) != ElasticSearchQuery.to_es:
warnings.warn(
"The .to_es() method on Elasticsearch query classes is deprecated. "
"Please rename {class_name}.to_es() to {class_name}.get_query()".format(
class_name=self.query.__class__.__name__
),
RemovedInWagtail14Warning, stacklevel=2)
body = {
'query': self.query.to_es(),
}
else:
body = {
'query': self.query.get_query()
}
if not for_count:
sort = self.query.get_sort()
if sort is not None:
body['sort'] = sort
return body
def _do_search(self):
# Params for elasticsearch query
params = dict(
index=self.backend.es_index,
body=dict(query=self.query.to_es()),
body=self._get_es_body(),
_source=False,
fields='pk',
from_=self.start,
@ -345,13 +420,10 @@ class ElasticSearchResults(BaseSearchResults):
return [results[str(pk)] for pk in pks if results[str(pk)]]
def _do_count(self):
# Get query
query = self.query.to_es()
# Get count
hit_count = self.backend.es.count(
index=self.backend.es_index,
body=dict(query=query),
body=self._get_es_body(for_count=True),
)['count']
# Add limits

Wyświetl plik

@ -0,0 +1,12 @@
from wagtail.wagtailsearch.backends import get_search_backend
class SearchableQuerySetMixin(object):
def search(self, query_string, fields=None,
operator=None, order_by_relevance=True, backend='default'):
"""
This runs a search query on all the items in the QuerySet
"""
search_backend = get_search_backend(backend)
return search_backend.search(query_string, self, fields=fields,
operator=operator, order_by_relevance=order_by_relevance)

Wyświetl plik

@ -167,6 +167,38 @@ class TestElasticSearchBackend(BackendTests, TestCase):
# Should find the result
self.assertEqual(len(results), 1)
def test_custom_ordering(self):
# Reset the index
self.backend.reset_index()
self.backend.add_type(models.SearchTest)
# Add some test data
# a is more relevant, but b is more recent
a = models.SearchTest()
a.title = "Hello Hello World"
a.live = True
a.published_date = datetime.date(2015, 10, 11)
a.save()
self.backend.add(a)
b = models.SearchTest()
b.title = "Hello World"
b.live = True
b.published_date = datetime.date(2015, 10, 12)
b.save()
self.backend.add(b)
# Refresh the index
self.backend.refresh_index()
# Do a search ordered by relevence
results = self.backend.search("Hello", models.SearchTest.objects.all())
self.assertEqual(list(results), [a, b])
# Do a search ordered by published date
results = self.backend.search("Hello", models.SearchTest.objects.order_by('-published_date'), order_by_relevance=False)
self.assertEqual(list(results), [b, a])
class TestElasticSearchQuery(TestCase):
def assertDictEqual(self, a, b):
@ -191,7 +223,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_none_query_string(self):
# Create a query
@ -199,7 +231,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'match_all': {}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_and_operator(self):
# Create a query
@ -207,7 +239,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials'], 'operator': 'and'}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_filter(self):
# Create a query
@ -215,7 +247,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'term': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_and_filter(self):
# Create a query
@ -225,7 +257,7 @@ class TestElasticSearchQuery(TestCase):
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'and': [{'term': {'live_filter': True}}, {'term': {'title_filter': 'Test'}}]}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
# Make sure field filters are sorted (as they can be in any order which may cause false positives)
query = query.to_es()
query = query.get_query()
field_filters = query['filtered']['filter']['and'][1]['and']
field_filters[:] = sorted(field_filters, key=lambda f: list(f['term'].keys())[0])
@ -236,7 +268,7 @@ class TestElasticSearchQuery(TestCase):
query = self.ElasticSearchQuery(models.SearchTest.objects.filter(Q(title="Test") | Q(live=True)), "Hello")
# Make sure field filters are sorted (as they can be in any order which may cause false positives)
query = query.to_es()
query = query.get_query()
field_filters = query['filtered']['filter']['and'][1]['or']
field_filters[:] = sorted(field_filters, key=lambda f: list(f['term'].keys())[0])
@ -250,7 +282,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'not': {'term': {'live_filter': True}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_fields(self):
# Create a query
@ -258,7 +290,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'match': {'title': 'Hello'}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_fields_with_and_operator(self):
# Create a query
@ -266,7 +298,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'prefix': {'content_type': 'searchtests_searchtest'}}, 'query': {'match': {'title': 'Hello', 'operator': 'and'}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_exact_lookup(self):
# Create a query
@ -274,7 +306,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'term': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_none_lookup(self):
# Create a query
@ -282,7 +314,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'missing': {'field': 'title_filter'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_isnull_true_lookup(self):
# Create a query
@ -290,7 +322,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'missing': {'field': 'title_filter'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_isnull_false_lookup(self):
# Create a query
@ -298,7 +330,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'not': {'missing': {'field': 'title_filter'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_startswith_lookup(self):
# Create a query
@ -306,7 +338,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'prefix': {'title_filter': 'Test'}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_gt_lookup(self):
# This also tests conversion of python dates to strings
@ -316,7 +348,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'gt': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_lt_lookup(self):
# Create a query
@ -324,7 +356,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'lt': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_gte_lookup(self):
# Create a query
@ -332,7 +364,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'gte': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_lte_lookup(self):
# Create a query
@ -340,7 +372,7 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'lte': '2014-04-29'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_range_lookup(self):
start_date = datetime.datetime(2014, 4, 29)
@ -351,7 +383,31 @@ class TestElasticSearchQuery(TestCase):
# Check it
expected_result = {'filtered': {'filter': {'and': [{'prefix': {'content_type': 'searchtests_searchtest'}}, {'range': {'published_date_filter': {'gte': '2014-04-29', 'lte': '2014-08-19'}}}]}, 'query': {'multi_match': {'query': 'Hello', 'fields': ['_all', '_partials']}}}}
self.assertDictEqual(query.to_es(), expected_result)
self.assertDictEqual(query.get_query(), expected_result)
def test_custom_ordering(self):
# Create a query
query = self.ElasticSearchQuery(models.SearchTest.objects.order_by('published_date'), "Hello", order_by_relevance=False)
# Check it
expected_result = [{'published_date_filter': 'asc'}]
self.assertDictEqual(query.get_sort(), expected_result)
def test_custom_ordering_reversed(self):
# Create a query
query = self.ElasticSearchQuery(models.SearchTest.objects.order_by('-published_date'), "Hello", order_by_relevance=False)
# Check it
expected_result = [{'published_date_filter': 'desc'}]
self.assertDictEqual(query.get_sort(), expected_result)
def test_custom_ordering_multiple(self):
# Create a query
query = self.ElasticSearchQuery(models.SearchTest.objects.order_by('published_date', 'live'), "Hello", order_by_relevance=False)
# Check it
expected_result = [{'published_date_filter': 'asc'}, {'live_filter': 'asc'}]
self.assertDictEqual(query.get_sort(), expected_result)
class TestElasticSearchResults(TestCase):
@ -382,7 +438,8 @@ class TestElasticSearchResults(TestCase):
backend = self.ElasticSearch({})
query = mock.MagicMock()
query.queryset = models.SearchTest.objects.all()
query.to_es.return_value = 'QUERY'
query.get_query.return_value = 'QUERY'
query.get_sort.return_value = None
return self.ElasticSearchResults(backend, query)
def construct_search_response(self, results):