Skip to content

Commit ca4d47a

Browse files
MadanThangavelutoastdriven
authored andcommitted
Haystack manager and tests
1 parent 7ac260e commit ca4d47a

File tree

5 files changed

+212
-23
lines changed

5 files changed

+212
-23
lines changed

haystack/indexes.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,13 @@ def __new__(cls, name, bases, attrs):
5656
shadow_facet_field.set_instance_name(shadow_facet_name)
5757
attrs['fields'][shadow_facet_name] = shadow_facet_field
5858

59-
# Assigning default 'objects' query manager
60-
try:
61-
attrs['objects'] = HaystackManager(attrs['meta'].index_label)
62-
except KeyError:
63-
attrs['objects'] = HaystackManager(DEFAULT_ALIAS)
64-
59+
# Assigning default 'objects' query manager if it does not already exist
60+
if not attrs.has_key('objects'):
61+
try:
62+
attrs['objects'] = HaystackManager(attrs['meta'].index_label)
63+
except KeyError:
64+
attrs['objects'] = HaystackManager(DEFAULT_ALIAS)
65+
6566
return super(DeclarativeMetaclass, cls).__new__(cls, name, bases, attrs)
6667

6768

haystack/manager.py

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
'''
2-
Created on Feb 20, 2012
3-
4-
@author: Madan Thangavelu
5-
'''
61
from haystack.query import SearchQuerySet, EmptySearchQuerySet
72

83
class HaystackManager(object):
@@ -21,30 +16,30 @@ def get_empty_query_set(self):
2116

2217
def all(self):
2318
return self.get_query_set()
24-
19+
2520
def none(self):
2621
return self.get_empty_query_set()
2722

2823
def filter(self, *args, **kwargs):
2924
return self.get_query_set().filter(*args, **kwargs)
3025

3126
def exclude(self, *args, **kwargs):
32-
return self.get_query_set().filter(*args, **kwargs)
27+
return self.get_query_set().exclude(*args, **kwargs)
3328

3429
def filter_and(self, *args, **kwargs):
35-
return self.get_query_set().filter(*args, **kwargs)
30+
return self.get_query_set().filter_and(*args, **kwargs)
3631

3732
def filter_or(self, *args, **kwargs):
38-
return self.get_query_set().filter(*args, **kwargs)
33+
return self.get_query_set().filter_or(*args, **kwargs)
3934

4035
def order_by(self, *args):
41-
return self.get_query_set().filter(*args)
36+
return self.get_query_set().order_by(*args)
4237

4338
def order_by_distance(self, **kwargs):
44-
return self.get_query_set().filter( **kwargs)
39+
return self.get_query_set().order_by_distance(**kwargs)
4540

4641
def highlight(self):
47-
return self.get_query_set().filter()
42+
return self.get_query_set().highlight()
4843

4944
def boost(self, term, boost):
5045
return self.get_query_set().boost(term, boost)
@@ -53,7 +48,7 @@ def facet(self, field):
5348
return self.get_query_set().facet(field)
5449

5550
def within(self, field, point_1, point_2):
56-
return self.get_query_set().filter(field, point_1, point_2)
51+
return self.get_query_set().within(field, point_1, point_2)
5752

5853
def dwithin(self, field, point, distance):
5954
return self.get_query_set().dwithin(field, point, distance)
@@ -71,13 +66,13 @@ def narrow(self, query):
7166
return self.get_query_set().narrow(query)
7267

7368
def raw_search(self, query_string, **kwargs):
74-
return self.get_query_set().filter(query_string, **kwargs)
69+
return self.get_query_set().raw_search(query_string, **kwargs)
7570

7671
def load_all(self):
7772
return self.get_query_set().load_all()
7873

7974
def auto_query(self, query_string, fieldname='content'):
80-
return self.get_query_set().filter(query_string, fieldname=fieldname)
75+
return self.get_query_set().auto_query(query_string, fieldname=fieldname)
8176

8277
def autocomplete(self, **kwargs):
8378
return self.get_query_set().autocomplete(**kwargs)

haystack/query.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,17 @@ def __init__(self, using=None, query=None):
3333
self._ignored_result_count = 0
3434
self.log = logging.getLogger('haystack')
3535

36-
def _determine_backend(self):
36+
def _determine_backend(self):
37+
from haystack import connections
3738
# A backend has been manually selected. Use it instead.
3839
if self._using is not None:
40+
if self.query:
41+
self.query = self.query.using(self._using)
42+
else:
43+
self.query = connections[self._using].get_query()
3944
return self._using
4045

4146
# No backend, so rely on the routers to figure out what's right.
42-
from haystack import connections
4347
hints = {}
4448

4549
if self.query:

tests/core/tests/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,4 @@
1515
from core.tests.views import *
1616
from core.tests.utils import *
1717
from core.tests.management_commands import *
18+
from core.tests.managers import *

tests/core/tests/managers.py

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
import datetime
2+
from django.test import TestCase
3+
from haystack import connections
4+
from haystack.models import SearchResult
5+
from haystack.exceptions import FacetingError
6+
from haystack.query import SearchQuerySet, EmptySearchQuerySet, ValuesSearchQuerySet, ValuesListSearchQuerySet
7+
from core.models import MockModel, AnotherMockModel, CharPKMockModel, AFifthMockModel
8+
from core.tests.views import BasicMockModelSearchIndex, BasicAnotherMockModelSearchIndex
9+
from core.tests.mocks import CharPKMockSearchBackend
10+
from haystack.utils.loading import UnifiedIndex
11+
from haystack.manager import HaystackManager
12+
13+
class CustomManager(HaystackManager):
14+
def filter(self, *args, **kwargs):
15+
return self.get_query_set().filter(content='foo1').filter(*args, **kwargs)
16+
17+
class CustomMockModelIndexWithObjectsManager(BasicMockModelSearchIndex):
18+
objects = CustomManager()
19+
20+
class CustomMockModelIndexWithAnotherManager(BasicMockModelSearchIndex):
21+
another = CustomManager()
22+
23+
class ManagerTestCase(TestCase):
24+
fixtures = ['bulk_data.json']
25+
26+
def setUp(self):
27+
super(ManagerTestCase, self).setUp()
28+
29+
self.search_index = BasicMockModelSearchIndex
30+
# Update the "index".
31+
backend = connections['default'].get_backend()
32+
backend.clear()
33+
backend.update(self.search_index(), MockModel.objects.all())
34+
35+
self.search_queryset = BasicMockModelSearchIndex.objects.all()
36+
37+
def test_queryset(self):
38+
self.assertTrue(isinstance(self.search_queryset, SearchQuerySet))
39+
40+
def test_none(self):
41+
self.assertTrue(isinstance(self.search_index.objects.none(), EmptySearchQuerySet))
42+
43+
def test_filter(self):
44+
sqs = self.search_index.objects.filter(content='foo')
45+
self.assertTrue(isinstance(sqs, SearchQuerySet))
46+
self.assertEqual(len(sqs.query.query_filter), 1)
47+
48+
def test_exclude(self):
49+
sqs = self.search_index.objects.exclude(content='foo')
50+
self.assertTrue(isinstance(sqs, SearchQuerySet))
51+
self.assertEqual(len(sqs.query.query_filter), 1)
52+
53+
def test_filter_and(self):
54+
sqs = self.search_index.objects.filter_and(content='foo')
55+
self.assertTrue(isinstance(sqs, SearchQuerySet))
56+
self.assertEqual(sqs.query.query_filter.connector, 'AND')
57+
58+
def test_filter_or(self):
59+
sqs = self.search_index.objects.filter_or(content='foo')
60+
self.assertTrue(isinstance(sqs, SearchQuerySet))
61+
self.assertEqual(sqs.query.query_filter.connector, 'OR')
62+
63+
def test_order_by(self):
64+
sqs = self.search_index.objects.order_by('foo')
65+
self.assertTrue(isinstance(sqs, SearchQuerySet))
66+
self.assertTrue('foo' in sqs.query.order_by)
67+
68+
def test_order_by_distance(self):
69+
# Not implemented
70+
pass
71+
72+
def test_highlight(self):
73+
sqs = self.search_index.objects.highlight()
74+
self.assertEqual(sqs.query.highlight, True)
75+
76+
def test_boost(self):
77+
sqs = self.search_index.objects.boost('foo', 10)
78+
self.assertTrue(isinstance(sqs, SearchQuerySet))
79+
self.assertEqual(len(sqs.query.boost.keys()), 1)
80+
81+
def test_facets(self):
82+
sqs = self.search_index.objects.facet('foo')
83+
self.assertTrue(isinstance(sqs, SearchQuerySet))
84+
self.assertEqual(len(sqs.query.facets), 1)
85+
86+
def test_within(self):
87+
# Not implemented
88+
pass
89+
90+
def test_dwithin(self):
91+
# Not implemented
92+
pass
93+
94+
def test_distance(self):
95+
# Not implemented
96+
pass
97+
98+
def test_date_facets(self):
99+
sqs = self.search_index.objects.date_facet('foo', start_date=datetime.date(2008, 2, 25), end_date=datetime.date(2009, 2, 25), gap_by='month')
100+
self.assertTrue(isinstance(sqs, SearchQuerySet))
101+
self.assertEqual(len(sqs.query.date_facets), 1)
102+
103+
def test_query_facets(self):
104+
sqs = self.search_index.objects.query_facet('foo', '[bar TO *]')
105+
self.assertTrue(isinstance(sqs, SearchQuerySet))
106+
self.assertEqual(len(sqs.query.query_facets), 1)
107+
108+
def test_narrow(self):
109+
sqs = self.search_index.objects.narrow("content:foo")
110+
self.assertTrue(isinstance(sqs, SearchQuerySet))
111+
self.assertSetEqual(set(['content:foo']), sqs.query.narrow_queries)
112+
113+
def test_raw_search(self):
114+
self.assertEqual(len(self.search_index.objects.raw_search('foo')), 23)
115+
116+
def test_load_all(self):
117+
# Models with character primary keys.
118+
sqs = self.search_index.objects.all()
119+
sqs.query.backend = CharPKMockSearchBackend('charpk')
120+
results = sqs.load_all().all()
121+
self.assertEqual(len(results._result_cache), 0)
122+
123+
def test_auto_query(self):
124+
sqs = self.search_index.objects.auto_query('test search -stuff')
125+
self.assertTrue(isinstance(sqs, SearchQuerySet))
126+
self.assertEqual(repr(sqs.query.query_filter), '<SQ: AND content__contains=test search -stuff>')
127+
128+
# With keyword argument
129+
sqs = self.search_index.objects.auto_query('test search -stuff', fieldname='title')
130+
self.assertTrue(isinstance(sqs, SearchQuerySet))
131+
self.assertEqual(repr(sqs.query.query_filter), "<SQ: AND title__contains=test search -stuff>")
132+
133+
def test_autocomplete(self):
134+
# Not implemented
135+
pass
136+
137+
def test_count(self):
138+
self.assertEqual(SearchQuerySet().count(), 23)
139+
self.assertEqual(self.search_index.objects.count(), 23)
140+
141+
def test_best_match(self):
142+
self.assertTrue(isinstance(self.search_index.objects.best_match(), SearchResult))
143+
144+
def test_latest(self):
145+
self.assertTrue(isinstance(self.search_index.objects.latest('pub_date'), SearchResult))
146+
147+
def test_more_like_this(self):
148+
mock = MockModel()
149+
mock.id = 1
150+
151+
self.assertEqual(len(self.search_index.objects.more_like_this(mock)), 23)
152+
153+
def test_facet_counts(self):
154+
self.assertEqual(self.search_index.objects.facet_counts(), {})
155+
156+
def spelling_suggestion(self):
157+
# Test the case where spelling support is disabled.
158+
sqs = self.search_index.objects.filter(content='Indx')
159+
self.assertEqual(sqs.spelling_suggestion(), None)
160+
self.assertEqual(sqs.spelling_suggestion(preferred_query=None), None)
161+
162+
def test_values(self):
163+
sqs = self.search_index.objects.auto_query("test").values("id")
164+
self.assert_(isinstance(sqs, ValuesSearchQuerySet))
165+
166+
def test_valueslist(self):
167+
sqs = self.search_index.objects.auto_query("test").values_list("id")
168+
self.assert_(isinstance(sqs, ValuesListSearchQuerySet))
169+
170+
class CustomManagerTestCase(TestCase):
171+
fixtures = ['bulk_data.json']
172+
173+
def setUp(self):
174+
super(CustomManagerTestCase, self).setUp()
175+
176+
self.search_index_1 = CustomMockModelIndexWithObjectsManager
177+
self.search_index_2 = CustomMockModelIndexWithAnotherManager
178+
179+
def test_filter_object_manager(self):
180+
sqs = self.search_index_1.objects.filter(content='foo')
181+
self.assertTrue(isinstance(sqs, SearchQuerySet))
182+
self.assertEqual(len(sqs.query.query_filter), 2)
183+
184+
def test_filter_another_manager(self):
185+
sqs = self.search_index_2.another.filter(content='foo')
186+
self.assertTrue(isinstance(sqs, SearchQuerySet))
187+
self.assertEqual(len(sqs.query.query_filter), 2)
188+

0 commit comments

Comments
 (0)