Skip to content

Commit 230607b

Browse files
Updated ObjectField to allow for unmapped keys (#302)
* Updated ObjectField to allow for unmapped keys * Moved is_iterable dict check * Removed unneeded space at start of line * Added tests for ObjectFields * Added comments explaining ObjectField changes Co-authored-by: Safwan Rahman <[email protected]>
1 parent 417c183 commit 230607b

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

django_elasticsearch_dsl/fields.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ def _get_inner_field_data(self, obj, field_value_to_ignore=None):
116116
obj, field_value_to_ignore
117117
)
118118

119+
# This allows for ObjectFields to be indexed from dicts with
120+
# dynamic keys (i.e. keys/fields not defined in 'properties')
121+
if not data and obj and isinstance(obj, dict):
122+
data = obj
123+
119124
return data
120125

121126
def get_value_from_instance(self, instance, field_value_to_ignore=None):
@@ -130,7 +135,9 @@ def get_value_from_instance(self, instance, field_value_to_ignore=None):
130135
except TypeError:
131136
is_iterable = False
132137

133-
if is_iterable:
138+
# While dicts are iterable, they need to be excluded here so
139+
# their full data is indexed
140+
if is_iterable and not isinstance(objs, dict):
134141
return [
135142
self._get_inner_field_data(obj, field_value_to_ignore)
136143
for obj in objs if obj != field_value_to_ignore

tests/test_fields.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,36 @@ def test_get_value_from_instance(self):
100100
'last_name': "bar",
101101
})
102102

103+
def test_get_value_from_instance_with_partial_properties(self):
104+
field = ObjectField(
105+
attr='person',
106+
properties={
107+
'first_name': TextField(analyzer='foo')
108+
}
109+
)
110+
111+
instance = NonCallableMock(
112+
person=NonCallableMock(first_name='foo', last_name='bar')
113+
)
114+
115+
self.assertEqual(field.get_value_from_instance(instance), {
116+
'first_name': "foo"
117+
})
118+
119+
def test_get_value_from_instance_without_properties(self):
120+
field = ObjectField(attr='person')
121+
122+
instance = NonCallableMock(
123+
person={'first_name': 'foo', 'last_name': 'bar'}
124+
)
125+
126+
self.assertEqual(field.get_value_from_instance(instance),
127+
{
128+
'first_name': "foo",
129+
'last_name': "bar"
130+
}
131+
)
132+
103133
def test_get_value_from_instance_with_inner_objectfield(self):
104134
field = ObjectField(attr='person', properties={
105135
'first_name': TextField(analyzer='foo'),
@@ -120,6 +150,30 @@ def test_get_value_from_instance_with_inner_objectfield(self):
120150
'additional': {'age': 12}
121151
})
122152

153+
def test_get_value_from_instance_with_inner_objectfield_without_properties(self):
154+
field = ObjectField(
155+
attr='person',
156+
properties={
157+
'first_name': TextField(analyzer='foo'),
158+
'last_name': TextField(),
159+
'additional': ObjectField()
160+
}
161+
)
162+
163+
instance = NonCallableMock(person=NonCallableMock(
164+
first_name="foo",
165+
last_name="bar",
166+
additional={'age': 12}
167+
))
168+
169+
self.assertEqual(field.get_value_from_instance(instance),
170+
{
171+
'first_name': "foo",
172+
'last_name': "bar",
173+
'additional': {'age': 12}
174+
}
175+
)
176+
123177
def test_get_value_from_instance_with_none_inner_objectfield(self):
124178
field = ObjectField(attr='person', properties={
125179
'first_name': TextField(analyzer='foo'),
@@ -168,6 +222,29 @@ def test_get_value_from_iterable(self):
168222
}
169223
])
170224

225+
def test_get_value_from_iterable_without_properties(self):
226+
field = ObjectField(attr='person')
227+
228+
instance = NonCallableMock(
229+
person=[
230+
{'first_name': "foo1", 'last_name': "bar1"},
231+
{'first_name': "foo2", 'last_name': "bar2"}
232+
]
233+
)
234+
235+
self.assertEqual(field.get_value_from_instance(instance),
236+
[
237+
{
238+
'first_name': "foo1",
239+
'last_name': "bar1",
240+
},
241+
{
242+
'first_name': "foo2",
243+
'last_name': "bar2",
244+
}
245+
]
246+
)
247+
171248

172249
class NestedFieldTestCase(TestCase):
173250
def test_get_mapping(self):

0 commit comments

Comments
 (0)