Skip to content

Commit

Permalink
Add optional multi parameter to Field.__init__ to indicate multi-valu…
Browse files Browse the repository at this point in the history
…e fields

Fixes elastic#83
Fixes elastic#95
  • Loading branch information
honzakral committed Mar 18, 2015
1 parent bc92629 commit 0d8261d
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 6 deletions.
20 changes: 19 additions & 1 deletion docs/persistence.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ The mapping definition follows a similar pattern to the query dsl:
m.field('category', 'string', fields={'raw': String(index='not_analyzed')})
# you can also create a field manually
comment = Nested().field('author', 'string').field('created_at', 'date')
comment = Nested()
comment.field('author', String())
comment.field('created_at', Date())
# and attach it to the mapping
m.field('comments', comment)
Expand All @@ -36,6 +38,15 @@ The mapping definition follows a similar pattern to the query dsl:
# save the mapping into index 'my-index'
m.save('my-index')
.. note::

By default all fields (with the exception of ``Nested``) will expect single
values. You can always override this expectation during the field
creation/definition by passing in ``multi=True`` into the constructor
(``m.field('tags', String(index='not_analyzed', multi=True))``). Then the
value of the field, even if the field hasn't been set, will be an empty
list enabling you to write ``doc.tags.append('search')``.

Especially if you are using dynamic mappings it might be useful to update the
mapping based on an existing type in Elasticsearch, or create the mapping
directly from an existing type:
Expand Down Expand Up @@ -87,6 +98,10 @@ If you want to create a model-like wrapper around your documents, use the
self.created_at = datetime.now()
return super().save(** kwargs)
Dcoument life cycle
~~~~~~~~~~~~~~~~~~~

To create a new ``Post`` document just instantiate the class and pass in any
fields you wish to set, you can then use standard attribute setting to
change/add more fields. Note that you are not limitted to the fields defined
Expand Down Expand Up @@ -138,6 +153,9 @@ To retrieve an existing document use the ``get`` class method:
# and save the changes into the cluster again
first.save()
Search
~~~~~~

To search for this document type, use the ``search`` class method:

.. code:: python
Expand Down
20 changes: 17 additions & 3 deletions elasticsearch_dsl/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,20 @@ class Field(DslBase):
_param_defs = {'fields': {'type': 'field', 'hash': True}}
name = None

def __init__(self, *args, **kwargs):
self._multi = kwargs.pop('multi', False)
super(Field, self).__init__(*args, **kwargs)

def _to_python(self, data):
return data

def _empty(self):
return None

def empty(self):
if self._multi:
return []
return self._empty()

def to_python(self, data):
if isinstance(data, (list, AttrList)):
Expand Down Expand Up @@ -73,7 +85,7 @@ def field(self, name, *args, **kwargs):
# XXX: backwards compatible, will be removed
property = field

def empty(self):
def _empty(self):
return {}

def update(self, other_object):
Expand Down Expand Up @@ -106,8 +118,10 @@ class Object(InnerObject, Field):
class Nested(InnerObject, Field):
name = 'nested'

def empty(self):
return []
def __init__(self, *args, **kwargs):
# change the default for Nested fields
kwargs.setdefault('multi', True)
super(Nested, self).__init__(*args, **kwargs)

class Date(Field):
name = 'date'
Expand Down
6 changes: 4 additions & 2 deletions elasticsearch_dsl/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -407,8 +407,10 @@ def __getattr__(self, name):
if name in self._doc_type.mapping:
f = self._doc_type.mapping[name]
if hasattr(f, 'empty'):
setattr(self, name, f.empty())
return getattr(self, name)
value = f.empty()
if value is not None:
setattr(self, name, value)
return getattr(self, name)
raise

def __setattr__(self, name, value):
Expand Down
11 changes: 11 additions & 0 deletions test_elasticsearch_dsl/test_document.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,17 @@ class Meta:
'_all': {'enabled': False}
}
} == User._doc_type.mapping.to_dict()

def test_multi_value_fields():
class Blog(document.DocType):
tags = field.String(multi=True, index='not_analyzed')

b = Blog()
assert [] == b.tags
b.tags.append('search')
b.tags.append('python')
assert ['search', 'python'] == b.tags

def test_docs_with_properties():
class User(document.DocType):
pwd_hash = field.String()
Expand Down

0 comments on commit 0d8261d

Please sign in to comment.