diff --git a/docs/changelog.rst b/docs/changelog.rst index 0843a35c..a312d1ef 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -2,6 +2,10 @@ Changelog ========= +Changes in 0.6.x +================ +- Promoted BaseDynamicField to DynamicField + Changes in 0.6.9 ================ - Fixed sparse indexes on inherited docs diff --git a/mongoengine/base.py b/mongoengine/base.py index ec7af453..75718223 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -435,47 +435,6 @@ class ComplexBaseField(BaseField): owner_document = property(_get_owner_document, _set_owner_document) -class BaseDynamicField(BaseField): - """Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data""" - - def to_mongo(self, value): - """Convert a Python type to a MongoDBcompatible type. - """ - - if isinstance(value, basestring): - return value - - if hasattr(value, 'to_mongo'): - return value.to_mongo() - - if not isinstance(value, (dict, list, tuple)): - return value - - is_list = False - if not hasattr(value, 'items'): - is_list = True - value = dict([(k, v) for k, v in enumerate(value)]) - - data = {} - for k, v in value.items(): - data[k] = self.to_mongo(v) - - if is_list: # Convert back to a list - value = [v for k, v in sorted(data.items(), key=operator.itemgetter(0))] - else: - value = data - return value - - def lookup_member(self, member_name): - return member_name - - def prepare_query_value(self, op, value): - if isinstance(value, basestring): - from mongoengine.fields import StringField - return StringField().prepare_query_value(op, value) - return self.to_mongo(value) - - class ObjectIdField(BaseField): """An field wrapper around MongoDB's ObjectIds. """ @@ -859,7 +818,8 @@ class BaseDocument(object): field = None if not hasattr(self, name) and not name.startswith('_'): - field = BaseDynamicField(db_field=name) + from fields import DynamicField + field = DynamicField(db_field=name) field.name = name self._dynamic_fields[name] = field diff --git a/mongoengine/document.py b/mongoengine/document.py index 9e281f5c..95b07d1b 100644 --- a/mongoengine/document.py +++ b/mongoengine/document.py @@ -1,4 +1,5 @@ import pymongo + from bson.dbref import DBRef from mongoengine import signals @@ -359,7 +360,7 @@ class DynamicDocument(Document): way as an ordinary document but has expando style properties. Any data passed or set against the :class:`~mongoengine.DynamicDocument` that is not a field is automatically converted into a - :class:`~mongoengine.BaseDynamicField` and data can be attributed to that + :class:`~mongoengine.DynamicField` and data can be attributed to that field. ..note:: diff --git a/mongoengine/fields.py b/mongoengine/fields.py index f88e5c19..c72c6cb4 100644 --- a/mongoengine/fields.py +++ b/mongoengine/fields.py @@ -30,7 +30,7 @@ except ImportError: __all__ = ['StringField', 'IntField', 'FloatField', 'BooleanField', 'DateTimeField', 'EmbeddedDocumentField', 'ListField', 'DictField', 'ObjectIdField', 'ReferenceField', 'ValidationError', 'MapField', - 'DecimalField', 'ComplexDateTimeField', 'URLField', + 'DecimalField', 'ComplexDateTimeField', 'URLField', 'DynamicField', 'GenericReferenceField', 'FileField', 'BinaryField', 'SortedListField', 'EmailField', 'GeoPointField', 'ImageField', 'SequenceField', 'UUIDField', 'GenericEmbeddedDocumentField'] @@ -473,6 +473,47 @@ class GenericEmbeddedDocumentField(BaseField): return data +class DynamicField(BaseField): + """Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data""" + + def to_mongo(self, value): + """Convert a Python type to a MongoDBcompatible type. + """ + + if isinstance(value, basestring): + return value + + if hasattr(value, 'to_mongo'): + return value.to_mongo() + + if not isinstance(value, (dict, list, tuple)): + return value + + is_list = False + if not hasattr(value, 'items'): + is_list = True + value = dict([(k, v) for k, v in enumerate(value)]) + + data = {} + for k, v in value.items(): + data[k] = self.to_mongo(v) + + if is_list: # Convert back to a list + value = [v for k, v in sorted(data.items(), key=itemgetter(0))] + else: + value = data + return value + + def lookup_member(self, member_name): + return member_name + + def prepare_query_value(self, op, value): + if isinstance(value, basestring): + from mongoengine.fields import StringField + return StringField().prepare_query_value(op, value) + return self.to_mongo(value) + + class ListField(ComplexBaseField): """A list field that wraps a standard field, allowing multiple instances of the field to be used as a list in the database. diff --git a/mongoengine/queryset.py b/mongoengine/queryset.py index a535553f..1fb3eda7 100644 --- a/mongoengine/queryset.py +++ b/mongoengine/queryset.py @@ -627,8 +627,8 @@ class QuerySet(object): if field_name in document._fields: field = document._fields[field_name] elif document._dynamic: - from base import BaseDynamicField - field = BaseDynamicField(db_field=field_name) + from fields import DynamicField + field = DynamicField(db_field=field_name) else: raise InvalidQueryError('Cannot resolve field "%s"' % field_name)