Merge branch 'master' into 0.8
Conflicts: AUTHORS docs/changelog.rst mongoengine/__init__.py mongoengine/base.py mongoengine/fields.py python-mongoengine.spec tests/test_document.py tests/test_fields.py tests/test_queryset.py
This commit is contained in:
		| @@ -58,6 +58,8 @@ class QuerySet(object): | ||||
|         self._read_preference = None | ||||
|         self._iter = False | ||||
|         self._scalar = [] | ||||
|         self._as_pymongo = False | ||||
|         self._as_pymongo_coerce = False | ||||
|  | ||||
|         # If inheritance is allowed, only return instances and instances of | ||||
|         # subclasses of the class being used | ||||
| @@ -178,11 +180,13 @@ class QuerySet(object): | ||||
|             if self._where_clause: | ||||
|                 self._cursor_obj.where(self._where_clause) | ||||
|  | ||||
|             # apply default ordering | ||||
|             if self._ordering: | ||||
|                 # Apply query ordering | ||||
|                 self._cursor_obj.sort(self._ordering) | ||||
|             elif self._document._meta['ordering']: | ||||
|                 # Otherwise, apply the ordering from the document model | ||||
|                 self.order_by(*self._document._meta['ordering']) | ||||
|                 self._cursor_obj.sort(self._ordering) | ||||
|  | ||||
|             if self._limit is not None: | ||||
|                 self._cursor_obj.limit(self._limit - (self._skip or 0)) | ||||
| @@ -328,7 +332,7 @@ class QuerySet(object): | ||||
|                 msg = ("Some documents inserted aren't instances of %s" | ||||
|                         % str(self._document)) | ||||
|                 raise OperationError(msg) | ||||
|             if doc.pk: | ||||
|             if doc.pk and not doc._created: | ||||
|                 msg = "Some documents have ObjectIds use doc.update() instead" | ||||
|                 raise OperationError(msg) | ||||
|             raw.append(doc.to_mongo()) | ||||
| @@ -388,6 +392,9 @@ class QuerySet(object): | ||||
|             for doc in docs: | ||||
|                 doc_map[doc['_id']] = self._get_scalar( | ||||
|                         self._document._from_son(doc)) | ||||
|         elif self._as_pymongo: | ||||
|             for doc in docs: | ||||
|                 doc_map[doc['_id']] = self._get_as_pymongo(doc) | ||||
|         else: | ||||
|             for doc in docs: | ||||
|                 doc_map[doc['_id']] = self._document._from_son(doc) | ||||
| @@ -404,6 +411,9 @@ class QuerySet(object): | ||||
|             if self._scalar: | ||||
|                 return self._get_scalar(self._document._from_son( | ||||
|                         self._cursor.next())) | ||||
|             if self._as_pymongo: | ||||
|                 return self._get_as_pymongo(self._cursor.next()) | ||||
|  | ||||
|             return self._document._from_son(self._cursor.next()) | ||||
|         except StopIteration, e: | ||||
|             self.rewind() | ||||
| @@ -592,6 +602,8 @@ class QuerySet(object): | ||||
|             if self._scalar: | ||||
|                 return self._get_scalar(self._document._from_son( | ||||
|                         self._cursor[key])) | ||||
|             if self._as_pymongo: | ||||
|                 return self._get_as_pymongo(self._cursor.next()) | ||||
|             return self._document._from_son(self._cursor[key]) | ||||
|         raise AttributeError | ||||
|  | ||||
| @@ -714,7 +726,7 @@ class QuerySet(object): | ||||
|             key_list.append((key, direction)) | ||||
|  | ||||
|         self._ordering = key_list | ||||
|         self._cursor.sort(key_list) | ||||
|  | ||||
|         return self | ||||
|  | ||||
|     def explain(self, format=False): | ||||
| @@ -887,6 +899,48 @@ class QuerySet(object): | ||||
|  | ||||
|         return tuple(data) | ||||
|  | ||||
|     def _get_as_pymongo(self, row): | ||||
|         # Extract which fields paths we should follow if .fields(...) was | ||||
|         # used. If not, handle all fields. | ||||
|         if not getattr(self, '__as_pymongo_fields', None): | ||||
|             self.__as_pymongo_fields = [] | ||||
|             for field in self._loaded_fields.fields - set(['_cls', '_id', '_types']): | ||||
|                 self.__as_pymongo_fields.append(field) | ||||
|                 while '.' in field: | ||||
|                     field, _ = field.rsplit('.', 1) | ||||
|                     self.__as_pymongo_fields.append(field) | ||||
|  | ||||
|         all_fields = not self.__as_pymongo_fields | ||||
|  | ||||
|         def clean(data, path=None): | ||||
|             path = path or '' | ||||
|  | ||||
|             if isinstance(data, dict): | ||||
|                 new_data = {} | ||||
|                 for key, value in data.iteritems(): | ||||
|                     new_path = '%s.%s' % (path, key) if path else key | ||||
|                     if all_fields or new_path in self.__as_pymongo_fields: | ||||
|                         new_data[key] = clean(value, path=new_path) | ||||
|                 data = new_data | ||||
|             elif isinstance(data, list): | ||||
|                 data = [clean(d, path=path) for d in data] | ||||
|             else: | ||||
|                 if self._as_pymongo_coerce: | ||||
|                     # If we need to coerce types, we need to determine the | ||||
|                     # type of this field and use the corresponding .to_python(...) | ||||
|                     from mongoengine.fields import EmbeddedDocumentField | ||||
|                     obj = self._document | ||||
|                     for chunk in path.split('.'): | ||||
|                         obj = getattr(obj, chunk, None) | ||||
|                         if obj is None: | ||||
|                             break | ||||
|                         elif isinstance(obj, EmbeddedDocumentField): | ||||
|                             obj = obj.document_type | ||||
|                     if obj and data is not None: | ||||
|                         data = obj.to_python(data) | ||||
|             return data | ||||
|         return clean(row) | ||||
|  | ||||
|     def scalar(self, *fields): | ||||
|         """Instead of returning Document instances, return either a specific | ||||
|         value or a tuple of values in order. | ||||
| @@ -909,6 +963,16 @@ class QuerySet(object): | ||||
|         """An alias for scalar""" | ||||
|         return self.scalar(*fields) | ||||
|  | ||||
|     def as_pymongo(self, coerce_types=False): | ||||
|         """Instead of returning Document instances, return raw values from | ||||
|         pymongo. | ||||
|  | ||||
|         :param coerce_type: Field types (if applicable) would be use to coerce types. | ||||
|         """ | ||||
|         self._as_pymongo = True | ||||
|         self._as_pymongo_coerce = coerce_types | ||||
|         return self | ||||
|  | ||||
|     def _sub_js_fields(self, code): | ||||
|         """When fields are specified with [~fieldname] syntax, where | ||||
|         *fieldname* is the Python name of a field, *fieldname* will be | ||||
|   | ||||
		Reference in New Issue
	
	Block a user