Updated .only() behaviour - now like exclude it is chainable (#202)
This commit is contained in:
@@ -7,11 +7,20 @@ class QueryFieldList(object):
|
||||
ONLY = 1
|
||||
EXCLUDE = 0
|
||||
|
||||
def __init__(self, fields=[], value=ONLY, always_include=[]):
|
||||
def __init__(self, fields=None, value=ONLY, always_include=None, _only_called=False):
|
||||
"""The QueryFieldList builder
|
||||
|
||||
:param fields: A list of fields used in `.only()` or `.exclude()`
|
||||
:param value: How to handle the fields; either `ONLY` or `EXCLUDE`
|
||||
:param always_include: Any fields to always_include eg `_cls`
|
||||
:param _only_called: Has `.only()` been called? If so its a set of fields
|
||||
otherwise it performs a union.
|
||||
"""
|
||||
self.value = value
|
||||
self.fields = set(fields)
|
||||
self.always_include = set(always_include)
|
||||
self.fields = set(fields or [])
|
||||
self.always_include = set(always_include or [])
|
||||
self._id = None
|
||||
self._only_called = _only_called
|
||||
self.slice = {}
|
||||
|
||||
def __add__(self, f):
|
||||
@@ -26,7 +35,10 @@ class QueryFieldList(object):
|
||||
self.slice = {}
|
||||
elif self.value is self.ONLY and f.value is self.ONLY:
|
||||
self._clean_slice()
|
||||
self.fields = self.fields.intersection(f.fields)
|
||||
if self._only_called:
|
||||
self.fields = self.fields.union(f.fields)
|
||||
else:
|
||||
self.fields = f.fields
|
||||
elif self.value is self.EXCLUDE and f.value is self.EXCLUDE:
|
||||
self.fields = self.fields.union(f.fields)
|
||||
self._clean_slice()
|
||||
@@ -46,6 +58,9 @@ class QueryFieldList(object):
|
||||
self.fields = self.fields.union(self.always_include)
|
||||
else:
|
||||
self.fields -= self.always_include
|
||||
|
||||
if getattr(f, '_only_called', False):
|
||||
self._only_called = True
|
||||
return self
|
||||
|
||||
def __nonzero__(self):
|
||||
|
||||
@@ -624,19 +624,35 @@ class QuerySet(object):
|
||||
|
||||
post = BlogPost.objects(...).only("title", "author.name")
|
||||
|
||||
.. note :: `only()` is chainable and will perform a union ::
|
||||
So with the following it will fetch both: `title` and `author.name`::
|
||||
|
||||
post = BlogPost.objects.only("title").only("author.name")
|
||||
|
||||
:func:`~mongoengine.queryset.QuerySet.all_fields` will reset any
|
||||
field filters.
|
||||
|
||||
:param fields: fields to include
|
||||
|
||||
.. versionadded:: 0.3
|
||||
.. versionchanged:: 0.5 - Added subfield support
|
||||
"""
|
||||
fields = dict([(f, QueryFieldList.ONLY) for f in fields])
|
||||
return self.fields(**fields)
|
||||
return self.fields(True, **fields)
|
||||
|
||||
def exclude(self, *fields):
|
||||
"""Opposite to .only(), exclude some document's fields. ::
|
||||
|
||||
post = BlogPost.objects(...).exclude("comments")
|
||||
|
||||
.. note :: `exclude()` is chainable and will perform a union ::
|
||||
So with the following it will exclude both: `title` and `author.name`::
|
||||
|
||||
post = BlogPost.objects.exclude("title").exclude("author.name")
|
||||
|
||||
:func:`~mongoengine.queryset.QuerySet.all_fields` will reset any
|
||||
field filters.
|
||||
|
||||
:param fields: fields to exclude
|
||||
|
||||
.. versionadded:: 0.5
|
||||
@@ -644,7 +660,7 @@ class QuerySet(object):
|
||||
fields = dict([(f, QueryFieldList.EXCLUDE) for f in fields])
|
||||
return self.fields(**fields)
|
||||
|
||||
def fields(self, **kwargs):
|
||||
def fields(self, _only_called=False, **kwargs):
|
||||
"""Manipulate how you load this document's fields. Used by `.only()`
|
||||
and `.exclude()` to manipulate which fields to retrieve. Fields also
|
||||
allows for a greater level of control for example:
|
||||
@@ -678,7 +694,8 @@ class QuerySet(object):
|
||||
for value, group in itertools.groupby(fields, lambda x: x[1]):
|
||||
fields = [field for field, value in group]
|
||||
fields = queryset._fields_to_dbfields(fields)
|
||||
queryset._loaded_fields += QueryFieldList(fields, value=value)
|
||||
queryset._loaded_fields += QueryFieldList(fields, value=value, _only_called=_only_called)
|
||||
|
||||
return queryset
|
||||
|
||||
def all_fields(self):
|
||||
|
||||
Reference in New Issue
Block a user