Skip to content

Commit f511c46

Browse files
committed
should_index: handle properties and BooleanFields
1 parent 2bf1ca4 commit f511c46

File tree

3 files changed

+91
-31
lines changed

3 files changed

+91
-31
lines changed

src/models.py

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ class AlgoliaIndex(object):
3838
# - a BooleanField
3939
# - a boolean property or attribute
4040
should_index = None
41+
# Name of the attribute to check on instances if should_index is not a callable
42+
_should_index_is_method = False
4143

4244
# Instance of the index from algoliasearch client
4345
__index = None
@@ -94,23 +96,20 @@ def __init__(self, model, client):
9496
raise AlgoliaIndexError('{} is not an attribute of {}.'.format(
9597
self.geo_field, model))
9698

97-
# Check should_index + get the callable
99+
# Check should_index + get the callable or attribute/field name
98100
if self.should_index:
99101
if hasattr(model, self.should_index):
100102
attr = getattr(model, self.should_index)
101-
if callable(attr):
103+
if type(attr) is not bool: # if attr is a bool, we keep attr=name to getattr on instance
102104
self.should_index = attr
103-
else:
104-
should_index_attr_name = self.should_index
105-
if isinstance(attr, bool):
106-
self.should_index = lambda instance: getattr(instance, should_index_attr_name) is True
107-
self.should_index._is_default = True
108-
else:
109-
raise AlgoliaIndexError('{} should be a bound callable or a boolean attribute.'.format(
110-
self.should_index))
105+
if callable(self.should_index):
106+
self._should_index_is_method = True
111107
else:
112-
raise AlgoliaIndexError('{} is not an attribute of {}.'.format(
113-
self.should_index, model))
108+
try:
109+
model._meta.get_field_by_name(self.should_index)
110+
except:
111+
raise AlgoliaIndexError('{} is not an attribute nor a field of {}.'.format(
112+
self.should_index, model))
114113

115114
def __set_index(self, client):
116115
'''Get an instance of Algolia Index'''
@@ -196,8 +195,8 @@ def _build_object(self, instance):
196195
return tmp
197196

198197
def update_obj_index(self, instance):
199-
'''Update the object.'''
200-
if self.should_index:
198+
"""Update the object."""
199+
if self._has_should_index():
201200
if not self._should_really_index(instance):
202201
# Should not index, but since we don't now the state of the
203202
# instance, we need to send a DELETE request to ensure that if
@@ -209,21 +208,40 @@ def update_obj_index(self, instance):
209208
self.__index.save_object(obj)
210209
logger.debug('UPDATE %s FROM %s', obj['objectID'], self.model)
211210

211+
def _has_should_index(self):
212+
"""Return True if this AlgoliaIndex has a should_index method or attribute"""
213+
return self.should_index is not None
214+
212215
def _should_index(self, instance):
213-
"""Return true if the object should be indexed (including when self.should_index is not set)."""
214-
if self.should_index:
216+
"""Return True if the object should be indexed (including when self.should_index is not set)."""
217+
if self._has_should_index():
215218
return self._should_really_index(instance)
216219
else:
217220
return True
218221

219222
def _should_really_index(self, instance):
220-
"""Return true if according to should_index the object should be indexed."""
221-
if hasattr(self.should_index, "__self__") or hasattr(self.should_index, '_is_default'):
222-
# bound method or lambda, let's use instance
223-
return self.should_index(instance)
223+
"""Return True if according to should_index the object should be indexed."""
224+
if self._should_index_is_method:
225+
if hasattr(self.should_index, "__self__"):
226+
# bound method, call with instance
227+
return self.should_index(instance)
228+
else:
229+
# unbound method, simply call without arguments
230+
return self.should_index()
224231
else:
225-
# unbound method, simply call without arguments
226-
return self.should_index()
232+
# property/attribute/Field, evaluate as bool
233+
attr_type = type(self.should_index)
234+
if attr_type is str:
235+
attr_value = getattr(instance, self.should_index)
236+
elif attr_type is property:
237+
attr_value = self.should_index.__get__(instance)
238+
else:
239+
raise AlgoliaIndexError('{} should be a boolean attribute or a method that returns a boolean.'.format(
240+
self.should_index))
241+
if type(attr_value) is not bool:
242+
raise AlgoliaIndexError("%s's should_index (%s) should be a boolean" % (
243+
instance.__class__.__name__, self.should_index))
244+
return attr_value
227245

228246
def delete_obj_index(self, instance):
229247
'''Delete the object.'''

tests/models.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,11 @@ def static_should_not_index():
3232
@property
3333
def property_should_index(self):
3434
return True
35+
36+
@property
37+
def property_should_not_index(self):
38+
return True
39+
40+
@property
41+
def property_string(self):
42+
return "foo"

tests/test_index.py

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ def setUp(self):
1515
name='SuperK',
1616
address='Finland',
1717
lat=63.3,
18-
lng=-32.0)
18+
lng=-32.0,
19+
is_admin=True)
1920
self.instance.category = ['Shop', 'Grocery']
2021
self.instance.locations = [
2122
{'lat': 10.3, 'lng': -20.0},
@@ -205,26 +206,59 @@ class ExampleIndex(AlgoliaIndex):
205206
fields = 'name'
206207
should_index = 'index_me'
207208
index = ExampleIndex(Example, self.client)
208-
obj = index._build_object(self.instance)
209209
self.assertTrue(index._should_index(self.instance),
210210
"We should index an instance when its should_index attr is True")
211211

212212
instance_should_not = Example()
213213
instance_should_not.index_me = False
214-
obj = index._build_object(instance_should_not)
215214
self.assertFalse(index._should_index(instance_should_not),
216215
"We should not index an instance when its should_index attr is False")
217216

218-
def test_should_index_field_raises(self):
217+
class ExampleIndex(AlgoliaIndex):
218+
fields = 'name'
219+
should_index = 'category'
220+
index = ExampleIndex(Example, self.client)
221+
with self.assertRaises(AlgoliaIndexError, msg="We should raise when the should_index attr is not boolean"):
222+
index._should_index(self.instance)
223+
224+
def test_should_index_field(self):
219225
class ExampleIndex(AlgoliaIndex):
220226
fields = 'name'
221227
should_index = 'is_admin'
222-
with self.assertRaises(AlgoliaIndexError):
223-
index = ExampleIndex(Example, self.client)
228+
index = ExampleIndex(Example, self.client)
229+
self.assertTrue(index._should_index(self.instance),
230+
"We should index an instance when its should_index field is True")
231+
232+
instance_should_not = Example()
233+
instance_should_not.is_admin = False
234+
self.assertFalse(index._should_index(instance_should_not),
235+
"We should not index an instance when its should_index field is False")
224236

225-
def test_should_index_property_raises(self):
237+
class ExampleIndex(AlgoliaIndex):
238+
fields = 'name'
239+
should_index = 'name'
240+
index = ExampleIndex(Example, self.client)
241+
with self.assertRaises(AlgoliaIndexError, msg="We should raise when the should_index field is not boolean"):
242+
index._should_index(self.instance)
243+
244+
def test_should_index_property(self):
226245
class ExampleIndex(AlgoliaIndex):
227246
fields = 'name'
228247
should_index = 'property_should_index'
229-
with self.assertRaises(AlgoliaIndexError):
230-
index = ExampleIndex(Example, self.client)
248+
index = ExampleIndex(Example, self.client)
249+
self.assertTrue(index._should_index(self.instance),
250+
"We should index an instance when its should_index property is True")
251+
252+
class ExampleIndex(AlgoliaIndex):
253+
fields = 'name'
254+
should_index = 'static_should_not_index'
255+
index = ExampleIndex(Example, self.client)
256+
self.assertFalse(index._should_index(self.instance),
257+
"We should not index an instance when its should_index property is False")
258+
259+
class ExampleIndex(AlgoliaIndex):
260+
fields = 'name'
261+
should_index = 'property_string'
262+
index = ExampleIndex(Example, self.client)
263+
with self.assertRaises(AlgoliaIndexError, msg="We should raise when the should_index property is not boolean"):
264+
index._should_index(self.instance)

0 commit comments

Comments
 (0)