Skip to content

Commit ad983dc

Browse files
author
Jorge Bastida
committed
Implement _get_as_pymongo
1 parent 94adc20 commit ad983dc

File tree

1 file changed

+48
-3
lines changed

1 file changed

+48
-3
lines changed

mongoengine/queryset.py

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ def __init__(self, document, collection):
354354
self._iter = False
355355
self._scalar = []
356356
self._as_pymongo = False
357+
self._as_pymongo_coerce = False
357358

358359
# If inheritance is allowed, only return instances and instances of
359360
# subclasses of the class being used
@@ -1003,9 +1004,8 @@ def next(self):
10031004
if self._scalar:
10041005
return self._get_scalar(self._document._from_son(
10051006
self._cursor.next()))
1006-
10071007
if self._as_pymongo:
1008-
return self._cursor.next()
1008+
return self._get_as_pymongo(self._cursor.next())
10091009

10101010
return self._document._from_son(self._cursor.next())
10111011
except StopIteration, e:
@@ -1585,6 +1585,48 @@ def lookup(obj, name):
15851585

15861586
return tuple(data)
15871587

1588+
def _get_as_pymongo(self, row):
1589+
# Extract which fields paths we should follow if .fields(...) was
1590+
# used. If not, handle all fields.
1591+
if not getattr(self, '__as_pymongo_fields', None):
1592+
self.__as_pymongo_fields = []
1593+
for field in self._loaded_fields.fields - set(['_cls', '_id', '_types']):
1594+
self.__as_pymongo_fields.append(field)
1595+
while '.' in field:
1596+
field, _ = field.rsplit('.', 1)
1597+
self.__as_pymongo_fields.append(field)
1598+
1599+
all_fields = not self.__as_pymongo_fields
1600+
1601+
def clean(data, path=None):
1602+
path = path or ''
1603+
1604+
if isinstance(data, dict):
1605+
new_data = {}
1606+
for key, value in data.iteritems():
1607+
new_path = '%s.%s' % (path, key) if path else key
1608+
if all_fields or new_path in self.__as_pymongo_fields:
1609+
new_data[key] = clean(value, path=new_path)
1610+
data = new_data
1611+
elif isinstance(data, list):
1612+
data = [clean(d, path=path) for d in data]
1613+
else:
1614+
if self._as_pymongo_coerce:
1615+
# If we need to coerce types, we need to determine the
1616+
# type of this field and use the corresponding .to_python(...)
1617+
from mongoengine.fields import EmbeddedDocumentField
1618+
obj = self._document
1619+
for chunk in path.split('.'):
1620+
obj = getattr(obj, chunk, None)
1621+
if obj is None:
1622+
break
1623+
elif isinstance(obj, EmbeddedDocumentField):
1624+
obj = obj.document_type
1625+
if obj and data is not None:
1626+
data = obj.to_python(data)
1627+
return data
1628+
return clean(row)
1629+
15881630
def scalar(self, *fields):
15891631
"""Instead of returning Document instances, return either a specific
15901632
value or a tuple of values in order.
@@ -1607,11 +1649,14 @@ def values_list(self, *fields):
16071649
"""An alias for scalar"""
16081650
return self.scalar(*fields)
16091651

1610-
def as_pymongo(self):
1652+
def as_pymongo(self, coerce_types=False):
16111653
"""Instead of returning Document instances, return raw values from
16121654
pymongo.
1655+
1656+
:param coerce_type: Field types (if applicable) would be use to coerce types.
16131657
"""
16141658
self._as_pymongo = True
1659+
self._as_pymongo_coerce = coerce_types
16151660
return self
16161661

16171662
def _sub_js_fields(self, code):

0 commit comments

Comments
 (0)