Skip to content
This repository was archived by the owner on Feb 20, 2019. It is now read-only.

Commit ba5bbb2

Browse files
FlorentFlorent Pigout
authored andcommitted
Refs #265 - Uses customizable id_field to index and get django object.
1 parent bcec897 commit ba5bbb2

File tree

5 files changed

+94
-21
lines changed

5 files changed

+94
-21
lines changed

elasticutils/contrib/django/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,9 @@ class MappingType(BaseMappingType):
197197
`get_model()`.
198198
199199
"""
200+
201+
id_field = 'pk'
202+
200203
def get_object(self):
201204
"""Returns the database object for this result
202205
@@ -205,7 +208,8 @@ def get_object(self):
205208
self.get_model().objects.get(pk=self._id)
206209
207210
"""
208-
return self.get_model().objects.get(pk=self._id)
211+
kwargs = {self.id_field: self._id}
212+
return self.get_model().objects.get(**kwargs)
209213

210214
@classmethod
211215
def get_model(cls):

elasticutils/contrib/django/tasks.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010

1111

1212
@task
13-
def index_objects(mapping_type, ids, chunk_size=100, es=None, index=None):
13+
def index_objects(mapping_type, ids, chunk_size=100, id_field='id', es=None,
14+
index=None):
1415
"""Index documents of a specified mapping type.
1516
1617
This allows for asynchronous indexing.
@@ -48,21 +49,24 @@ def update_in_index(sender, instance, **kw):
4849

4950
# Get the model this mapping type is based on.
5051
model = mapping_type.get_model()
52+
filter_key = '{0}__in'.format(id_field)
5153

5254
# Retrieve all the objects that we're going to index and do it in
5355
# bulk.
5456
for id_list in chunked(ids, chunk_size):
5557
documents = []
5658

57-
for obj in model.objects.filter(id__in=id_list):
59+
for obj in model.objects.filter(**{filter_key: id_list}):
5860
try:
59-
documents.append(mapping_type.extract_document(obj.id, obj))
60-
except Exception as exc:
61+
_id = str(getattr(obj, id_field))
62+
documents.append(mapping_type.extract_document(_id, obj))
63+
except StandardError as exc:
6164
log.exception('Unable to extract document {0}: {1}'.format(
6265
obj, repr(exc)))
6366

6467
if documents:
65-
mapping_type.bulk_index(documents, id_field='id', es=es, index=index)
68+
mapping_type.bulk_index(documents, id_field=id_field, es=es,
69+
index=index)
6670

6771

6872
@task

elasticutils/contrib/django/tests/__init__.py

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# We need to put these in a separate module so they're easy to import
22
# on a test-by-test basis so that we can skip django-requiring tests
33
# if django isn't installed.
4+
from uuid import UUID
45

56

67
from elasticutils.contrib.django import MappingType, Indexable
@@ -22,14 +23,20 @@ class SearchQuerySet(object):
2223
# Yes. This is kind of crazy, but ... whatever.
2324
def __init__(self, model):
2425
self.model = model
26+
self.id_field = model.id_field
2527
self.steps = []
2628

27-
def get(self, pk):
28-
pk = int(pk)
29-
return [m for m in _model_cache if m.id == pk][0]
30-
31-
def filter(self, id__in=None):
32-
self.steps.append(('filter', id__in))
29+
def get(self, pk=None, uuid=None):
30+
if pk:
31+
pk = int(pk)
32+
return [m for m in _model_cache if m.id == pk][0]
33+
if uuid:
34+
uuid = UUID(uuid)
35+
return [m for m in _model_cache if m.uuid == uuid][0]
36+
return []
37+
38+
def filter(self, id__in=None, uuid__in=None):
39+
self.steps.append(('filter', id__in or uuid__in))
3340
return self
3441

3542
def order_by(self, *fields):
@@ -47,7 +54,8 @@ def __iter__(self):
4754

4855
for mem in self.steps:
4956
if mem[0] == 'filter':
50-
objs = [obj for obj in objs if obj.id in mem[1]]
57+
objs = [obj for obj in objs
58+
if getattr(obj, self.id_field) in mem[1]]
5159
elif mem[0] == 'order_by':
5260
order_by_field = mem[1][0]
5361
elif mem[0] == 'values_list':
@@ -58,16 +66,16 @@ def __iter__(self):
5866

5967
if values_list:
6068
# Note: Hard-coded to just id and flat
61-
objs = [obj.id for obj in objs]
69+
objs = [getattr(obj, self.id_field) for obj in objs]
6270
return iter(objs)
6371

6472

6573
class Manager(object):
6674
def get_query_set(self):
6775
return SearchQuerySet(self)
6876

69-
def get(self, pk):
70-
return self.get_query_set().get(pk)
77+
def get(self, pk=None, uuid=None):
78+
return self.get_query_set().get(pk=pk, uuid=uuid)
7179

7280
def filter(self, *args, **kwargs):
7381
return self.get_query_set().filter(*args, **kwargs)
@@ -84,6 +92,7 @@ class FakeModel(object):
8492
objects = Manager()
8593

8694
def __init__(self, **kw):
95+
self.objects.id_field = kw.pop('id_field', 'id')
8796
self._doc = kw
8897
for key in kw:
8998
setattr(self, key, kw[key])
@@ -102,3 +111,12 @@ def extract_document(cls, obj_id, obj=None):
102111
'what to do with these args.')
103112

104113
return obj._doc
114+
115+
class FakeDjangoWithUuidMappingType(FakeDjangoMappingType):
116+
id_field = 'uuid'
117+
118+
@classmethod
119+
def extract_document(cls, obj_id, obj=None):
120+
doc = super(FakeDjangoWithUuidMappingType, cls)\
121+
.extract_document(obj_id, obj=obj)
122+
return {k:str(v) for k,v in doc.iteritems()}

elasticutils/contrib/django/tests/test_models.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import uuid
2+
13
from nose.tools import eq_
24

35
from elasticutils.contrib.django import S, get_es
46
from elasticutils.contrib.django.tests import (
5-
FakeDjangoMappingType, FakeModel, reset_model_cache)
7+
FakeDjangoMappingType, FakeDjangoWithUuidMappingType, FakeModel,
8+
reset_model_cache)
69
from elasticutils.contrib.django.estestcase import ESTestCase
710

811

@@ -20,12 +23,13 @@ def tearDown(self):
2023
IndexableTest.cleanup_index(FakeDjangoMappingType.get_index())
2124
reset_model_cache()
2225

23-
def persist_data(self, data):
26+
def persist_data(self, data, id_field='id'):
2427
for doc in data:
25-
FakeModel(**doc)
28+
FakeModel(id_field=id_field, **doc)
2629

2730
# Index the document with .index()
28-
FakeDjangoMappingType.index(doc, id_=doc['id'])
31+
FakeDjangoMappingType.index({k:str(v) for k,v in doc.iteritems()},
32+
id_=str(doc[id_field]))
2933

3034
self.refresh(FakeDjangoMappingType.get_index())
3135

@@ -51,6 +55,17 @@ def test_get_object(self):
5155
obj = s[0]
5256
eq_(obj.object.id, 1)
5357

58+
def test_get_object_with_custom_pk(self):
59+
data = [
60+
{'uuid': uuid.uuid4(), 'name': 'odin skullcrusher'},
61+
{'uuid': uuid.uuid4(), 'name': 'olaf bloodbiter'},
62+
]
63+
self.persist_data(data, id_field='uuid')
64+
65+
s = S(FakeDjangoWithUuidMappingType).query(name__prefix='odin')
66+
obj = s[0]
67+
eq_(obj.object.uuid, data[0]['uuid'])
68+
5469
def test_get_indexable(self):
5570
self.persist_data([
5671
{'id': 1, 'name': 'odin skullcrusher'},

elasticutils/contrib/django/tests/test_tasks.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import uuid
2+
13
from nose.tools import eq_
24

35
from elasticutils.contrib.django import get_es
46
from elasticutils.contrib.django.tasks import index_objects, unindex_objects
57
from elasticutils.contrib.django.tests import (
6-
FakeDjangoMappingType, FakeModel, reset_model_cache)
8+
FakeDjangoMappingType, FakeDjangoWithUuidMappingType, FakeModel,
9+
reset_model_cache)
710
from elasticutils.contrib.django.estestcase import ESTestCase
811

912

@@ -86,3 +89,32 @@ def bulk_index(cls, *args, **kwargs):
8689
index_objects(MockMappingType, [1, 2, 3], es='crazy_es', index='crazy_index')
8790
eq_(MockMappingType.index_kwarg, 'crazy_index')
8891
eq_(MockMappingType.es_kwarg, 'crazy_es')
92+
93+
def test_tasks_with_custom_id_field(self):
94+
docs = [
95+
{'uuid': uuid.uuid4(), 'name': 'odin skullcrusher'},
96+
{'uuid': uuid.uuid4(), 'name': 'heimdall kneebiter'},
97+
{'uuid': uuid.uuid4(), 'name': 'erik rose'}
98+
]
99+
100+
for d in docs:
101+
FakeModel(id_field='uuid', **d)
102+
103+
ids = [d['uuid'] for d in docs]
104+
105+
# Test index_objects task
106+
index_objects(FakeDjangoWithUuidMappingType, ids)
107+
FakeDjangoWithUuidMappingType.refresh_index()
108+
# nothing was indexed because a StandardError was catched silently,
109+
# may be explicit should be better.
110+
eq_(FakeDjangoWithUuidMappingType.search().count(), 0)
111+
112+
# Test everything has been indexed
113+
index_objects(FakeDjangoWithUuidMappingType, ids, id_field='uuid')
114+
FakeDjangoWithUuidMappingType.refresh_index()
115+
eq_(FakeDjangoWithUuidMappingType.search().count(), 3)
116+
117+
# Test unindex_objects task
118+
unindex_objects(FakeDjangoWithUuidMappingType, ids)
119+
FakeDjangoWithUuidMappingType.refresh_index()
120+
eq_(FakeDjangoWithUuidMappingType.search().count(), 0)

0 commit comments

Comments
 (0)