Skip to content

Commit 1b47512

Browse files
committed
Fetching a list of all fields now produces correct results regardless of dict-ordering. Thanks to carljm & veselosky for the report!
1 parent 347e08c commit 1b47512

File tree

3 files changed

+52
-5
lines changed

3 files changed

+52
-5
lines changed

haystack/fields.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def __init__(self, model_attr=None, use_template=False, template_name=None,
3030
self._default = default
3131
self.null = null
3232
self.index_fieldname = index_fieldname
33+
self.is_multivalued = False
3334

3435
self.set_instance_name(None)
3536

@@ -203,6 +204,10 @@ def convert(self, value):
203204

204205

205206
class MultiValueField(SearchField):
207+
def __init__(self, **kwargs):
208+
super(MultiValueField, self).__init__(**kwargs)
209+
self.is_multivalued = True
210+
206211
def prepare(self, obj):
207212
return self.convert(super(MultiValueField, self).prepare(obj))
208213

haystack/sites.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,17 @@ def all_searchfields(self):
9797
if not field_object.index_fieldname in fields:
9898
fields[field_object.index_fieldname] = field_object
9999
else:
100-
# FIXME: This needs to handle verifying the field type is
101-
# the same.
102-
# FIXME: This needs to handle some of the other field
103-
# options, like ``use_template``.
104-
100+
# If the field types are different, we can mostly
101+
# safely ignore this. The exception is ``MultiValueField``,
102+
# in which case we'll use it instead, copying over the
103+
# values.
104+
if field_object.is_multivalued == True:
105+
old_field = fields[field_object.index_fieldname]
106+
fields[field_object.index_fieldname] = field_object
107+
108+
# Switch it so we don't have to dupe the remaining
109+
# checks.
110+
field_object = old_field
105111

106112
# We've already got this field in the list. Ensure that
107113
# what we hand back is a superset of all options that
@@ -114,6 +120,12 @@ def all_searchfields(self):
114120

115121
if field_object.faceted is True:
116122
fields[field_object.index_fieldname].faceted = True
123+
124+
if field_object.use_template is True:
125+
fields[field_object.index_fieldname].use_template = True
126+
127+
if field_object.null is True:
128+
fields[field_object.index_fieldname].null = True
117129

118130
return fields
119131

tests/core/tests/sites.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,12 @@ class AlternateValidSearchIndex(SearchIndex):
4141
title = CharField(faceted=True)
4242

4343

44+
class MultiValueValidSearchIndex(SearchIndex):
45+
text = CharField(document=True)
46+
author = MultiValueField(stored=False)
47+
title = CharField(indexed=False)
48+
49+
4450
class SearchSiteTestCase(TestCase):
4551
def setUp(self):
4652
super(SearchSiteTestCase, self).setUp()
@@ -124,6 +130,7 @@ def test_all_searchfields(self):
124130
self.assertEqual(fields['author'].document, False)
125131
self.assertEqual(fields['author'].use_template, False)
126132
self.assertEqual(fields['author'].faceted, True)
133+
self.assertEqual(fields['author'].stored, True)
127134
self.assertEqual(fields['author'].index_fieldname, 'author')
128135

129136
self.site.unregister(MockModel)
@@ -152,6 +159,29 @@ def test_all_searchfields(self):
152159
self.assertEqual(fields['name'].faceted, False)
153160
self.assertEqual(fields['name'].index_fieldname, 'name')
154161

162+
self.site.unregister(AnotherMockModel)
163+
self.site.register(AnotherMockModel, MultiValueValidSearchIndex)
164+
fields = self.site.all_searchfields()
165+
self.assertEqual(len(fields), 4)
166+
self.assertEqual(sorted(fields.keys()), ['author', 'name', 'text', 'title'])
167+
self.assert_('text' in fields)
168+
self.assert_(isinstance(fields['text'], CharField))
169+
self.assertEqual(fields['text'].document, True)
170+
self.assertEqual(fields['text'].use_template, False)
171+
self.assert_('title' in fields)
172+
self.assert_(isinstance(fields['title'], CharField))
173+
self.assertEqual(fields['title'].document, False)
174+
self.assertEqual(fields['title'].use_template, False)
175+
self.assertEqual(fields['title'].faceted, True)
176+
self.assertEqual(fields['title'].indexed, True)
177+
self.assert_('author' in fields)
178+
self.assert_(isinstance(fields['author'], MultiValueField))
179+
self.assertEqual(fields['author'].document, False)
180+
self.assertEqual(fields['author'].use_template, False)
181+
self.assertEqual(fields['author'].stored, False)
182+
self.assertEqual(fields['author'].faceted, False)
183+
self.assertEqual(fields['author'].index_fieldname, 'author')
184+
155185
self.site.unregister(AnotherMockModel)
156186
self.site.register(AnotherMockModel, InvalidSearchIndex)
157187
self.assertRaises(SearchFieldError, self.site.all_searchfields)

0 commit comments

Comments
 (0)