Merge branch 'master' into 0.7
Conflicts: mongoengine/base.py
This commit is contained in:
		| @@ -12,7 +12,7 @@ from signals import * | ||||
| __all__ = (document.__all__ + fields.__all__ + connection.__all__ + | ||||
|            queryset.__all__ + signals.__all__) | ||||
|  | ||||
| VERSION = (0, 6, 18) | ||||
| VERSION = (0, 6, 20) | ||||
|  | ||||
|  | ||||
| def get_version(): | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import operator | ||||
| import sys  | ||||
| import sys | ||||
| import warnings | ||||
|  | ||||
| from collections import defaultdict | ||||
| @@ -16,7 +16,6 @@ import pymongo | ||||
| from bson import ObjectId | ||||
| from bson.dbref import DBRef | ||||
|  | ||||
|  | ||||
| class NotRegistered(Exception): | ||||
|     pass | ||||
|  | ||||
| @@ -112,6 +111,7 @@ class ValidationError(AssertionError): | ||||
|  | ||||
|  | ||||
| _document_registry = {} | ||||
| _module_registry = {} | ||||
|  | ||||
|  | ||||
| def get_document(name): | ||||
| @@ -199,7 +199,8 @@ class BaseField(object): | ||||
|         """Descriptor for assigning a value to a field in a document. | ||||
|         """ | ||||
|         instance._data[self.name] = value | ||||
|         instance._mark_as_changed(self.name) | ||||
|         if instance._initialised: | ||||
|             instance._mark_as_changed(self.name) | ||||
|  | ||||
|     def error(self, message="", errors=None, field_name=None): | ||||
|         """Raises a ValidationError. | ||||
| @@ -264,7 +265,7 @@ class ComplexBaseField(BaseField): | ||||
|     """ | ||||
|  | ||||
|     field = None | ||||
|     _dereference = False | ||||
|     __dereference = False | ||||
|  | ||||
|     def __get__(self, instance, owner): | ||||
|         """Descriptor to automatically dereference references. | ||||
| @@ -276,8 +277,6 @@ class ComplexBaseField(BaseField): | ||||
|         dereference = self.field is None or isinstance(self.field, | ||||
|             (GenericReferenceField, ReferenceField)) | ||||
|         if not self._dereference and instance._initialised and dereference: | ||||
|             from dereference import DeReference | ||||
|             self._dereference = DeReference()  # Cached | ||||
|             instance._data[self.name] = self._dereference( | ||||
|                 instance._data.get(self.name), max_depth=1, instance=instance, | ||||
|                 name=self.name | ||||
| @@ -293,14 +292,13 @@ class ComplexBaseField(BaseField): | ||||
|             value = BaseDict(value, instance, self.name) | ||||
|             instance._data[self.name] = value | ||||
|  | ||||
|         if self._dereference and instance._initialised and \ | ||||
|             isinstance(value, (BaseList, BaseDict)) and not value._dereferenced: | ||||
|         if (instance._initialised and isinstance(value, (BaseList, BaseDict)) | ||||
|             and not value._dereferenced): | ||||
|             value = self._dereference( | ||||
|                 value, max_depth=1, instance=instance, name=self.name | ||||
|             ) | ||||
|             value._dereferenced = True | ||||
|             instance._data[self.name] = value | ||||
|  | ||||
|         return value | ||||
|  | ||||
|     def __set__(self, instance, value): | ||||
| @@ -441,6 +439,13 @@ class ComplexBaseField(BaseField): | ||||
|  | ||||
|     owner_document = property(_get_owner_document, _set_owner_document) | ||||
|  | ||||
|     @property | ||||
|     def _dereference(self,): | ||||
|         if not self.__dereference: | ||||
|             from dereference import DeReference | ||||
|             self.__dereference = DeReference()  # Cached | ||||
|         return self.__dereference | ||||
|  | ||||
|  | ||||
| class ObjectIdField(BaseField): | ||||
|     """An field wrapper around MongoDB's ObjectIds. | ||||
| @@ -473,6 +478,7 @@ class DocumentMetaclass(type): | ||||
|     """ | ||||
|  | ||||
|     def __new__(cls, name, bases, attrs): | ||||
|  | ||||
|         def _get_mixin_fields(base): | ||||
|             attrs = {} | ||||
|             attrs.update(dict([(k, v) for k, v in base.__dict__.items() | ||||
| @@ -501,9 +507,7 @@ class DocumentMetaclass(type): | ||||
|         class_name = [name] | ||||
|         superclasses = {} | ||||
|         simple_class = True | ||||
|  | ||||
|         for base in bases: | ||||
|  | ||||
|             # Include all fields present in superclasses | ||||
|             if hasattr(base, '_fields'): | ||||
|                 doc_fields.update(base._fields) | ||||
| @@ -543,20 +547,18 @@ class DocumentMetaclass(type): | ||||
|         if not simple_class and not meta['allow_inheritance'] and not meta['abstract']: | ||||
|             raise ValueError('Only direct subclasses of Document may set ' | ||||
|                              '"allow_inheritance" to False') | ||||
|         attrs['_meta'] = meta | ||||
|         attrs['_class_name'] = doc_class_name | ||||
|         attrs['_superclasses'] = superclasses | ||||
|  | ||||
|         # Add the document's fields to the _fields attribute | ||||
|         field_names = {} | ||||
|         for attr_name, attr_value in attrs.items(): | ||||
|             if hasattr(attr_value, "__class__") and \ | ||||
|                issubclass(attr_value.__class__, BaseField): | ||||
|                 attr_value.name = attr_name | ||||
|                 if not attr_value.db_field: | ||||
|                     attr_value.db_field = attr_name | ||||
|                 doc_fields[attr_name] = attr_value | ||||
|                 field_names[attr_value.db_field] = field_names.get(attr_value.db_field, 0) + 1 | ||||
|         for attr_name, attr_value in attrs.iteritems(): | ||||
|             if not isinstance(attr_value, BaseField): | ||||
|                 continue | ||||
|             attr_value.name = attr_name | ||||
|             if not attr_value.db_field: | ||||
|                 attr_value.db_field = attr_name | ||||
|             doc_fields[attr_name] = attr_value | ||||
|  | ||||
|             field_names[attr_value.db_field] = field_names.get(attr_value.db_field, 0) + 1 | ||||
|  | ||||
|         duplicate_db_fields = [k for k, v in field_names.items() if v > 1] | ||||
|         if duplicate_db_fields: | ||||
| @@ -564,11 +566,24 @@ class DocumentMetaclass(type): | ||||
|         attrs['_fields'] = doc_fields | ||||
|         attrs['_db_field_map'] = dict([(k, v.db_field) for k, v in doc_fields.items() if k != v.db_field]) | ||||
|         attrs['_reverse_db_field_map'] = dict([(v, k) for k, v in attrs['_db_field_map'].items()]) | ||||
|         attrs['_meta'] = meta | ||||
|         attrs['_class_name'] = doc_class_name | ||||
|         attrs['_superclasses'] = superclasses | ||||
|  | ||||
|         from mongoengine import Document, EmbeddedDocument, DictField | ||||
|         if 'Document' not in _module_registry: | ||||
|             from mongoengine.document import Document, EmbeddedDocument | ||||
|             from mongoengine.fields import DictField | ||||
|             _module_registry['Document'] = Document | ||||
|             _module_registry['EmbeddedDocument'] = EmbeddedDocument | ||||
|             _module_registry['DictField'] = DictField | ||||
|         else: | ||||
|             Document = _module_registry.get('Document') | ||||
|             EmbeddedDocument = _module_registry.get('EmbeddedDocument') | ||||
|             DictField = _module_registry.get('DictField') | ||||
|  | ||||
|         new_class = super_new(cls, name, bases, attrs) | ||||
|         for field in new_class._fields.values(): | ||||
|  | ||||
|         for field in new_class._fields.itervalues(): | ||||
|             field.owner_document = new_class | ||||
|  | ||||
|             delete_rule = getattr(field, 'reverse_delete_rule', DO_NOTHING) | ||||
| @@ -605,12 +620,12 @@ class DocumentMetaclass(type): | ||||
|         global _document_registry | ||||
|         _document_registry[doc_class_name] = new_class | ||||
|  | ||||
|         # in Python 2, User-defined methods objects have special read-only  | ||||
|         # attributes 'im_func' and 'im_self' which contain the function obj  | ||||
|         # in Python 2, User-defined methods objects have special read-only | ||||
|         # attributes 'im_func' and 'im_self' which contain the function obj | ||||
|         # and class instance object respectively.  With Python 3 these special | ||||
|         # attributes have been replaced by __func__ and __self__.  The Blinker | ||||
|         # module continues to use im_func and im_self, so the code below | ||||
|         # copies __func__ into im_func and __self__ into im_self for  | ||||
|         # copies __func__ into im_func and __self__ into im_self for | ||||
|         # classmethod objects in Document derived classes. | ||||
|         if PY3: | ||||
|             for key, val in new_class.__dict__.items(): | ||||
| @@ -738,7 +753,7 @@ class TopLevelDocumentMetaclass(DocumentMetaclass): | ||||
|         unique_indexes = cls._unique_with_indexes(new_class) | ||||
|         new_class._meta['unique_indexes'] = unique_indexes | ||||
|  | ||||
|         for field_name, field in new_class._fields.items(): | ||||
|         for field_name, field in new_class._fields.iteritems(): | ||||
|             # Check for custom primary key | ||||
|             if field.primary_key: | ||||
|                 current_pk = new_class._meta['id_field'] | ||||
| @@ -809,21 +824,23 @@ class BaseDocument(object): | ||||
|         self._data = {} | ||||
|  | ||||
|         # Assign default values to instance | ||||
|         for attr_name, field in self._fields.items(): | ||||
|             value = getattr(self, attr_name, None) | ||||
|             setattr(self, attr_name, value) | ||||
|         for key, field in self._fields.iteritems(): | ||||
|             if self._db_field_map.get(key, key) in values: | ||||
|                 continue | ||||
|             value = getattr(self, key, None) | ||||
|             setattr(self, key, value) | ||||
|  | ||||
|         # Set passed values after initialisation | ||||
|         if self._dynamic: | ||||
|             self._dynamic_fields = {} | ||||
|             dynamic_data = {} | ||||
|             for key, value in values.items(): | ||||
|             for key, value in values.iteritems(): | ||||
|                 if key in self._fields or key == '_id': | ||||
|                     setattr(self, key, value) | ||||
|                 elif self._dynamic: | ||||
|                     dynamic_data[key] = value | ||||
|         else: | ||||
|             for key, value in values.items(): | ||||
|             for key, value in values.iteritems(): | ||||
|                 key = self._reverse_db_field_map.get(key, key) | ||||
|                 setattr(self, key, value) | ||||
|  | ||||
| @@ -832,7 +849,7 @@ class BaseDocument(object): | ||||
|  | ||||
|         if self._dynamic: | ||||
|             self._dynamic_lock = False | ||||
|             for key, value in dynamic_data.items(): | ||||
|             for key, value in dynamic_data.iteritems(): | ||||
|                 setattr(self, key, value) | ||||
|  | ||||
|         # Flag initialised | ||||
|   | ||||
| @@ -34,7 +34,9 @@ class DeReference(object): | ||||
|  | ||||
|         doc_type = None | ||||
|         if instance and instance._fields: | ||||
|             doc_type = instance._fields[name].field | ||||
|             doc_type = instance._fields[name] | ||||
|             if hasattr(doc_type, 'field'): | ||||
|                 doc_type = doc_type.field | ||||
|  | ||||
|             if isinstance(doc_type, ReferenceField): | ||||
|                 doc_type = doc_type.document_type | ||||
|   | ||||
| @@ -1333,7 +1333,7 @@ class UUIDField(BaseField): | ||||
|         super(UUIDField, self).__init__(**kwargs) | ||||
|  | ||||
|     def to_python(self, value): | ||||
|         if not self.binary: | ||||
|         if not self._binary: | ||||
|             if not isinstance(value, basestring): | ||||
|                 value = unicode(value) | ||||
|             return uuid.UUID(value) | ||||
|   | ||||
| @@ -329,6 +329,7 @@ class QuerySet(object): | ||||
|     """ | ||||
|  | ||||
|     __already_indexed = set() | ||||
|     __dereference = False | ||||
|  | ||||
|     def __init__(self, document, collection): | ||||
|         self._document = document | ||||
| @@ -600,7 +601,6 @@ class QuerySet(object): | ||||
|  | ||||
|             if self._hint != -1: | ||||
|                 self._cursor_obj.hint(self._hint) | ||||
|  | ||||
|         return self._cursor_obj | ||||
|  | ||||
|     @classmethod | ||||
| @@ -765,8 +765,22 @@ class QuerySet(object): | ||||
|             key = '.'.join(parts) | ||||
|             if op is None or key not in mongo_query: | ||||
|                 mongo_query[key] = value | ||||
|             elif key in mongo_query and isinstance(mongo_query[key], dict): | ||||
|                 mongo_query[key].update(value) | ||||
|             elif key in mongo_query: | ||||
|                 if isinstance(mongo_query[key], dict) and isinstance(value, dict): | ||||
|                     mongo_query[key].update(value) | ||||
|                 elif isinstance(mongo_query[key], list): | ||||
|                     mongo_query[key].append(value) | ||||
|                 else: | ||||
|                     mongo_query[key] = [mongo_query[key], value] | ||||
|  | ||||
|         for k, v in mongo_query.items(): | ||||
|             if isinstance(v, list): | ||||
|                 value = [{k:val} for val in v] | ||||
|                 if '$and' in mongo_query.keys(): | ||||
|                     mongo_query['$and'].append(value) | ||||
|                 else: | ||||
|                     mongo_query['$and'] = value | ||||
|                 del mongo_query[k] | ||||
|  | ||||
|         return mongo_query | ||||
|  | ||||
| @@ -1152,9 +1166,10 @@ class QuerySet(object): | ||||
|  | ||||
|         .. versionadded:: 0.4 | ||||
|         .. versionchanged:: 0.5 - Fixed handling references | ||||
|         .. versionchanged:: 0.6 - Improved db_field refrence handling | ||||
|         """ | ||||
|         from dereference import DeReference | ||||
|         return DeReference()(self._cursor.distinct(field), 1) | ||||
|         return self._dereference(self._cursor.distinct(field), 1, | ||||
|                                  name=field, instance=self._document) | ||||
|  | ||||
|     def only(self, *fields): | ||||
|         """Load only a subset of this document's fields. :: | ||||
| @@ -1854,13 +1869,30 @@ class QuerySet(object): | ||||
|  | ||||
|         .. versionadded:: 0.5 | ||||
|         """ | ||||
|         from dereference import DeReference | ||||
|         # Make select related work the same for querysets | ||||
|         max_depth += 1 | ||||
|         return DeReference()(self, max_depth=max_depth) | ||||
|         return self._dereference(self, max_depth=max_depth) | ||||
|  | ||||
|     @property | ||||
|     def _dereference(self): | ||||
|         if not self.__dereference: | ||||
|             from dereference import DeReference | ||||
|             self.__dereference = DeReference()  # Cached | ||||
|         return self.__dereference | ||||
|  | ||||
|  | ||||
| class QuerySetManager(object): | ||||
|     """ | ||||
|     The default QuerySet Manager. | ||||
|  | ||||
|     Custom QuerySet Manager functions can extend this class and users can | ||||
|     add extra queryset functionality.  Any custom manager methods must accept a | ||||
|     :class:`~mongoengine.Document` class as its first argument, and a | ||||
|     :class:`~mongoengine.queryset.QuerySet` as its second argument. | ||||
|  | ||||
|     The method function should return a :class:`~mongoengine.queryset.QuerySet` | ||||
|     , probably the same one that was passed in, but modified in some way. | ||||
|     """ | ||||
|  | ||||
|     get_queryset = None | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user