@@ -354,6 +354,7 @@ def __init__(self, document, collection):
354
354
self ._iter = False
355
355
self ._scalar = []
356
356
self ._as_pymongo = False
357
+ self ._as_pymongo_coerce = False
357
358
358
359
# If inheritance is allowed, only return instances and instances of
359
360
# subclasses of the class being used
@@ -1003,9 +1004,8 @@ def next(self):
1003
1004
if self ._scalar :
1004
1005
return self ._get_scalar (self ._document ._from_son (
1005
1006
self ._cursor .next ()))
1006
-
1007
1007
if self ._as_pymongo :
1008
- return self ._cursor .next ()
1008
+ return self ._get_as_pymongo ( self . _cursor .next () )
1009
1009
1010
1010
return self ._document ._from_son (self ._cursor .next ())
1011
1011
except StopIteration , e :
@@ -1585,6 +1585,48 @@ def lookup(obj, name):
1585
1585
1586
1586
return tuple (data )
1587
1587
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
+
1588
1630
def scalar (self , * fields ):
1589
1631
"""Instead of returning Document instances, return either a specific
1590
1632
value or a tuple of values in order.
@@ -1607,11 +1649,14 @@ def values_list(self, *fields):
1607
1649
"""An alias for scalar"""
1608
1650
return self .scalar (* fields )
1609
1651
1610
- def as_pymongo (self ):
1652
+ def as_pymongo (self , coerce_types = False ):
1611
1653
"""Instead of returning Document instances, return raw values from
1612
1654
pymongo.
1655
+
1656
+ :param coerce_type: Field types (if applicable) would be use to coerce types.
1613
1657
"""
1614
1658
self ._as_pymongo = True
1659
+ self ._as_pymongo_coerce = coerce_types
1615
1660
return self
1616
1661
1617
1662
def _sub_js_fields (self , code ):
0 commit comments