Skip to content
Browse files

Whoosh: allow multiple order_by() fields

The Whoosh backend previously prevented the use of more than one
order_by field. It now allows multiple fields as long as every field
uses the same sort direction.

Thanks to @qris, @overflow for the patch

Closes #627
Closes #919
1 parent c802df8 commit 6d3daa65848351663dc520a4440a1331557c9001 @acdha acdha committed
Showing with 25 additions and 14 deletions.
  1. +2 −0 AUTHORS
  2. +3 −2 haystack/backends/
  3. +20 −12 tests/whoosh_tests/tests/
@@ -87,3 +87,5 @@ Thanks to
* Artem Kostiuk (postatum) for patch allowing to search for slash character in ElasticSearch since Lucene 4.0.
* Luis Barrueco (luisbarrueco) for a simple fix regarding updating indexes using multiple backends.
* Szymon Teżewski (jasisz) for an update to the bounding-box calculation for spatial queries
+ * Chris Wilson (qris) and Orlando Fiol (overflow) for an update allowing the use of multiple order_by()
+ fields with Whoosh as long as they share a consistent sort direction
5 haystack/backends/
@@ -325,8 +325,9 @@ def search(self, query_string, sort_by=None, start_offset=0, end_offset=None,
if order_by.startswith('-'):
reverse_counter += 1
- if len(sort_by) > 1 and reverse_counter > 1:
- raise SearchBackendError("Whoosh does not handle more than one field and any field being ordered in reverse.")
+ if reverse_counter and reverse_counter != len(sort_by):
+ raise SearchBackendError("Whoosh requires all order_by fields"
+ " to use the same sort direction")
for order_by in sort_by:
if order_by.startswith('-'):
32 tests/whoosh_tests/tests/
@@ -1,21 +1,23 @@
-from datetime import timedelta
-from decimal import Decimal
import os
import shutil
-from whoosh.fields import TEXT, KEYWORD, NUMERIC, DATETIME, BOOLEAN
-from whoosh.qparser import QueryParser
+from datetime import timedelta
+from decimal import Decimal
from django.conf import settings
-from django.utils.datetime_safe import datetime, date
-from django.utils import unittest
from django.test import TestCase
-from haystack import connections, connection_router, reset_search_queries
-from haystack import indexes
+from django.utils import unittest
+from django.utils.datetime_safe import date, datetime
+from whoosh.fields import BOOLEAN, DATETIME, KEYWORD, NUMERIC, TEXT
+from whoosh.qparser import QueryParser
+from core.models import AFourthMockModel, AnotherMockModel, MockModel
+from core.tests.mocks import MockSearchResult
+from haystack import connections, indexes, reset_search_queries
+from haystack.exceptions import SearchBackendError
from haystack.inputs import AutoQuery
from haystack.models import SearchResult
from haystack.query import SearchQuerySet, SQ
from haystack.utils.loading import UnifiedIndex
-from core.models import MockModel, AnotherMockModel, AFourthMockModel
-from core.tests.mocks import MockSearchResult
class WhooshMockSearchIndex(indexes.SearchIndex, indexes.Indexable):
@@ -315,6 +317,13 @@ def test_order_by(self):
results ='*', sort_by=['-id'])
self.assertEqual([ for result in results['results']], [u'9', u'8', u'7', u'6', u'5', u'4', u'3', u'23', u'22', u'21', u'20', u'2', u'19', u'18', u'17', u'16', u'15', u'14', u'13', u'12', u'11', u'10', u'1'])
+ results ='*', sort_by=['-pub_date', '-id'])
+ self.assertEqual([ for result in results['results']],
+ [u'23', u'22', u'21', u'20', u'19', u'18', u'17', u'16', u'15', u'14', u'13', u'12',
+ u'11', u'10', u'9', u'8', u'7', u'6', u'5', u'4', u'2', u'3', u'1' ])
+ self.assertRaises(SearchBackendError,, u'*', sort_by=['-pub_date', 'id'])
def test__from_python(self):
self.assertEqual('abc'), u'abc')
self.assertEqual(, 1)
@@ -736,7 +745,7 @@ def test_cache_is_full(self):
self.assertEqual(len(connections['default'].queries), 0)
self.assertEqual(self.sqs._cache_is_full(), False)
results = self.sqs.auto_query('Indexed!')
- fire_the_iterator_and_fill_cache = [result for result in results]
+ [result for result in results]
self.assertEqual(results._cache_is_full(), True)
self.assertEqual(len(connections['default'].queries), 1)
@@ -786,7 +795,6 @@ def setUp(self):
super(LiveWhooshMultiSearchQuerySetTestCase, self).setUp()
# Stow.
- temp_path = os.path.join('tmp', 'test_whoosh_query')
self.old_whoosh_path = settings.HAYSTACK_CONNECTIONS['default']['PATH']
self.old_ui = connections['default'].get_unified_index()
self.ui = UnifiedIndex()

0 comments on commit 6d3daa6

Please sign in to comment.
Something went wrong with that request. Please try again.