@@ -67,7 +67,6 @@ def __init__(self, document, collection):
6767 self ._scalar = []
6868 self ._none = False
6969 self ._as_pymongo = False
70- self ._as_pymongo_coerce = False
7170 self ._search_text = None
7271
7372 # If inheritance is allowed, only return instances and instances of
@@ -728,11 +727,12 @@ def _clone_into(self, new_qs):
728727 '%s is not a subclass of BaseQuerySet' % new_qs .__name__ )
729728
730729 copy_props = ('_mongo_query' , '_initial_query' , '_none' , '_query_obj' ,
731- '_where_clause' , '_loaded_fields' , '_ordering' , '_snapshot' ,
732- '_timeout ' , '_class_check ' , '_slave_okay ' , '_read_preference ' ,
733- '_iter ' , '_scalar ' , '_as_pymongo ' , '_as_pymongo_coerce ' ,
730+ '_where_clause' , '_loaded_fields' , '_ordering' ,
731+ '_snapshot ' , '_timeout ' , '_class_check ' , '_slave_okay ' ,
732+ '_read_preference ' , '_iter ' , '_scalar ' , '_as_pymongo ' ,
734733 '_limit' , '_skip' , '_hint' , '_auto_dereference' ,
735- '_search_text' , 'only_fields' , '_max_time_ms' , '_comment' )
734+ '_search_text' , 'only_fields' , '_max_time_ms' ,
735+ '_comment' )
736736
737737 for prop in copy_props :
738738 val = getattr (self , prop )
@@ -939,7 +939,8 @@ def fields(self, _only_called=False, **kwargs):
939939
940940 posts = BlogPost.objects(...).fields(slice__comments=5)
941941
942- :param kwargs: A set keywors arguments identifying what to include.
942+ :param kwargs: A set of keyword arguments identifying what to
943+ include, exclude, or slice.
943944
944945 .. versionadded:: 0.5
945946 """
@@ -1128,16 +1129,15 @@ def values_list(self, *fields):
11281129 """An alias for scalar"""
11291130 return self .scalar (* fields )
11301131
1131- def as_pymongo (self , coerce_types = False ):
1132+ def as_pymongo (self ):
11321133 """Instead of returning Document instances, return raw values from
11331134 pymongo.
11341135
1135- :param coerce_types: Field types ( if applicable) would be use to
1136- coerce types .
1136+ This method is particularly useful if you don't need dereferencing
1137+ and care primarily about the speed of data retrieval .
11371138 """
11381139 queryset = self .clone ()
11391140 queryset ._as_pymongo = True
1140- queryset ._as_pymongo_coerce = coerce_types
11411141 return queryset
11421142
11431143 def max_time_ms (self , ms ):
@@ -1799,59 +1799,25 @@ def lookup(obj, name):
17991799
18001800 return tuple (data )
18011801
1802- def _get_as_pymongo (self , row ):
1803- # Extract which fields paths we should follow if .fields(...) was
1804- # used. If not, handle all fields.
1805- if not getattr (self , '__as_pymongo_fields' , None ):
1806- self .__as_pymongo_fields = []
1807-
1808- for field in self ._loaded_fields .fields - set (['_cls' ]):
1809- self .__as_pymongo_fields .append (field )
1810- while '.' in field :
1811- field , _ = field .rsplit ('.' , 1 )
1812- self .__as_pymongo_fields .append (field )
1813-
1814- all_fields = not self .__as_pymongo_fields
1815-
1816- def clean (data , path = None ):
1817- path = path or ''
1818-
1819- if isinstance (data , dict ):
1820- new_data = {}
1821- for key , value in data .iteritems ():
1822- new_path = '%s.%s' % (path , key ) if path else key
1823-
1824- if all_fields :
1825- include_field = True
1826- elif self ._loaded_fields .value == QueryFieldList .ONLY :
1827- include_field = new_path in self .__as_pymongo_fields
1828- else :
1829- include_field = new_path not in self .__as_pymongo_fields
1802+ def _get_as_pymongo (self , doc ):
1803+ """Clean up a PyMongo doc, removing fields that were only fetched
1804+ for the sake of MongoEngine's implementation, and return it.
1805+ """
1806+ # Always remove _cls as a MongoEngine's implementation detail.
1807+ if '_cls' in doc :
1808+ del doc ['_cls' ]
1809+
1810+ # If the _id was not included in a .only or was excluded in a .exclude,
1811+ # remove it from the doc (we always fetch it so that we can properly
1812+ # construct documents).
1813+ fields = self ._loaded_fields
1814+ if fields and '_id' in doc and (
1815+ (fields .value == QueryFieldList .ONLY and '_id' not in fields .fields ) or
1816+ (fields .value == QueryFieldList .EXCLUDE and '_id' in fields .fields )
1817+ ):
1818+ del doc ['_id' ]
18301819
1831- if include_field :
1832- new_data [key ] = clean (value , path = new_path )
1833- data = new_data
1834- elif isinstance (data , list ):
1835- data = [clean (d , path = path ) for d in data ]
1836- else :
1837- if self ._as_pymongo_coerce :
1838- # If we need to coerce types, we need to determine the
1839- # type of this field and use the corresponding
1840- # .to_python(...)
1841- EmbeddedDocumentField = _import_class ('EmbeddedDocumentField' )
1842-
1843- obj = self ._document
1844- for chunk in path .split ('.' ):
1845- obj = getattr (obj , chunk , None )
1846- if obj is None :
1847- break
1848- elif isinstance (obj , EmbeddedDocumentField ):
1849- obj = obj .document_type
1850- if obj and data is not None :
1851- data = obj .to_python (data )
1852- return data
1853-
1854- return clean (row )
1820+ return doc
18551821
18561822 def _sub_js_fields (self , code ):
18571823 """When fields are specified with [~fieldname] syntax, where
0 commit comments