redo fix for ListField loses use_db_field when serializing #1217
The new fix reverted the change on BaseField to_mongo so that it will not force new field class to add kwargs to to_mongo function. The new derived field class to_mongo can support use_db_field and fields parameters as needed. Basically all field classes derived from ComplexBaseField support those parameters.
This commit is contained in:
		| @@ -309,7 +309,7 @@ class BaseDocument(object): | |||||||
|         data = SON() |         data = SON() | ||||||
|         data["_id"] = None |         data["_id"] = None | ||||||
|         data['_cls'] = self._class_name |         data['_cls'] = self._class_name | ||||||
|         EmbeddedDocumentField = _import_class("EmbeddedDocumentField") |          | ||||||
|         # only root fields ['test1.a', 'test2'] => ['test1', 'test2'] |         # only root fields ['test1.a', 'test2'] => ['test1', 'test2'] | ||||||
|         root_fields = set([f.split('.')[0] for f in fields]) |         root_fields = set([f.split('.')[0] for f in fields]) | ||||||
|  |  | ||||||
| @@ -324,18 +324,20 @@ class BaseDocument(object): | |||||||
|                 field = self._dynamic_fields.get(field_name) |                 field = self._dynamic_fields.get(field_name) | ||||||
|  |  | ||||||
|             if value is not None: |             if value is not None: | ||||||
|  |                 f_inputs = field.to_mongo.__code__.co_varnames | ||||||
|                 if fields: |                 ex_vars = {} | ||||||
|  |                 if fields and 'fields' in f_inputs: | ||||||
|                     key = '%s.' % field_name |                     key = '%s.' % field_name | ||||||
|                     embedded_fields = [ |                     embedded_fields = [ | ||||||
|                         i.replace(key, '') for i in fields |                         i.replace(key, '') for i in fields | ||||||
|                         if i.startswith(key)] |                         if i.startswith(key)] | ||||||
|  |  | ||||||
|                 else: |                     ex_vars['fields'] = embedded_fields  | ||||||
|                     embedded_fields = [] |  | ||||||
|  |  | ||||||
|                 value = field.to_mongo(value, use_db_field=use_db_field, |                 if 'use_db_field' in f_inputs: | ||||||
|                                         fields=embedded_fields) |                     ex_vars['use_db_field'] = use_db_field | ||||||
|  |                       | ||||||
|  |                 value = field.to_mongo(value, **ex_vars) | ||||||
|  |  | ||||||
|             # Handle self generating fields |             # Handle self generating fields | ||||||
|             if value is None and field._auto_gen: |             if value is None and field._auto_gen: | ||||||
|   | |||||||
| @@ -158,11 +158,24 @@ class BaseField(object): | |||||||
|         """ |         """ | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         """Convert a Python type to a MongoDB-compatible type. |         """Convert a Python type to a MongoDB-compatible type. | ||||||
|         """ |         """ | ||||||
|         return self.to_python(value) |         return self.to_python(value) | ||||||
|  |  | ||||||
|  |     def _to_mongo_safe_call(self, value, use_db_field=True, fields=None): | ||||||
|  |         """A helper method to call to_mongo with proper inputs | ||||||
|  |         """ | ||||||
|  |         f_inputs = self.to_mongo.__code__.co_varnames | ||||||
|  |         ex_vars = {} | ||||||
|  |         if 'fields' in f_inputs: | ||||||
|  |             ex_vars['fields'] = fields  | ||||||
|  |  | ||||||
|  |         if 'use_db_field' in f_inputs: | ||||||
|  |             ex_vars['use_db_field'] = use_db_field | ||||||
|  |               | ||||||
|  |         return self.to_mongo(value, **ex_vars) | ||||||
|  |  | ||||||
|     def prepare_query_value(self, op, value): |     def prepare_query_value(self, op, value): | ||||||
|         """Prepare a value that is being used in a query for PyMongo. |         """Prepare a value that is being used in a query for PyMongo. | ||||||
|         """ |         """ | ||||||
| @@ -324,7 +337,7 @@ class ComplexBaseField(BaseField): | |||||||
|                                          key=operator.itemgetter(0))] |                                          key=operator.itemgetter(0))] | ||||||
|         return value_dict |         return value_dict | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value, use_db_field=True, fields=None): | ||||||
|         """Convert a Python type to a MongoDB-compatible type. |         """Convert a Python type to a MongoDB-compatible type. | ||||||
|         """ |         """ | ||||||
|         Document = _import_class("Document") |         Document = _import_class("Document") | ||||||
| @@ -336,10 +349,9 @@ class ComplexBaseField(BaseField): | |||||||
|  |  | ||||||
|         if hasattr(value, 'to_mongo'): |         if hasattr(value, 'to_mongo'): | ||||||
|             if isinstance(value, Document): |             if isinstance(value, Document): | ||||||
|                 return GenericReferenceField().to_mongo( |                 return GenericReferenceField().to_mongo(value) | ||||||
|                     value, **kwargs) |  | ||||||
|             cls = value.__class__ |             cls = value.__class__ | ||||||
|             val = value.to_mongo(**kwargs) |             val = value.to_mongo(use_db_field, fields) | ||||||
|             # If it's a document that is not inherited add _cls |             # If it's a document that is not inherited add _cls | ||||||
|             if isinstance(value, EmbeddedDocument): |             if isinstance(value, EmbeddedDocument): | ||||||
|                 val['_cls'] = cls.__name__ |                 val['_cls'] = cls.__name__ | ||||||
| @@ -354,7 +366,7 @@ class ComplexBaseField(BaseField): | |||||||
|                 return value |                 return value | ||||||
|  |  | ||||||
|         if self.field: |         if self.field: | ||||||
|             value_dict = dict([(key, self.field.to_mongo(item, **kwargs)) |             value_dict = dict([(key, self.field._to_mongo_safe_call(item, use_db_field, fields)) | ||||||
|                                for key, item in value.iteritems()]) |                                for key, item in value.iteritems()]) | ||||||
|         else: |         else: | ||||||
|             value_dict = {} |             value_dict = {} | ||||||
| @@ -373,20 +385,19 @@ class ComplexBaseField(BaseField): | |||||||
|                         meta.get('allow_inheritance', ALLOW_INHERITANCE) |                         meta.get('allow_inheritance', ALLOW_INHERITANCE) | ||||||
|                         is True) |                         is True) | ||||||
|                     if not allow_inheritance and not self.field: |                     if not allow_inheritance and not self.field: | ||||||
|                         value_dict[k] = GenericReferenceField().to_mongo( |                         value_dict[k] = GenericReferenceField().to_mongo(v) | ||||||
|                             v, **kwargs) |  | ||||||
|                     else: |                     else: | ||||||
|                         collection = v._get_collection_name() |                         collection = v._get_collection_name() | ||||||
|                         value_dict[k] = DBRef(collection, v.pk) |                         value_dict[k] = DBRef(collection, v.pk) | ||||||
|                 elif hasattr(v, 'to_mongo'): |                 elif hasattr(v, 'to_mongo'): | ||||||
|                     cls = v.__class__ |                     cls = v.__class__ | ||||||
|                     val = v.to_mongo(**kwargs) |                     val = v.to_mongo(use_db_field, fields) | ||||||
|                     # If it's a document that is not inherited add _cls |                     # If it's a document that is not inherited add _cls | ||||||
|                     if isinstance(v, (Document, EmbeddedDocument)): |                     if isinstance(v, (Document, EmbeddedDocument)): | ||||||
|                         val['_cls'] = cls.__name__ |                         val['_cls'] = cls.__name__ | ||||||
|                     value_dict[k] = val |                     value_dict[k] = val | ||||||
|                 else: |                 else: | ||||||
|                     value_dict[k] = self.to_mongo(v, **kwargs) |                     value_dict[k] = self.to_mongo(v, use_db_field, fields) | ||||||
|  |  | ||||||
|         if is_list:  # Convert back to a list |         if is_list:  # Convert back to a list | ||||||
|             return [v for _, v in sorted(value_dict.items(), |             return [v for _, v in sorted(value_dict.items(), | ||||||
| @@ -444,7 +455,7 @@ class ObjectIdField(BaseField): | |||||||
|             pass |             pass | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         if not isinstance(value, ObjectId): |         if not isinstance(value, ObjectId): | ||||||
|             try: |             try: | ||||||
|                 return ObjectId(unicode(value)) |                 return ObjectId(unicode(value)) | ||||||
| @@ -619,7 +630,7 @@ class GeoJsonBaseField(BaseField): | |||||||
|         if errors: |         if errors: | ||||||
|             return "Invalid MultiPolygon:\n%s" % ", ".join(errors) |             return "Invalid MultiPolygon:\n%s" % ", ".join(errors) | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         if isinstance(value, dict): |         if isinstance(value, dict): | ||||||
|             return value |             return value | ||||||
|         return SON([("type", self._type), ("coordinates", value)]) |         return SON([("type", self._type), ("coordinates", value)]) | ||||||
|   | |||||||
| @@ -231,7 +231,7 @@ class LongField(BaseField): | |||||||
|             pass |             pass | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         return Int64(value) |         return Int64(value) | ||||||
|  |  | ||||||
|     def validate(self, value): |     def validate(self, value): | ||||||
| @@ -338,7 +338,7 @@ class DecimalField(BaseField): | |||||||
|             return value |             return value | ||||||
|         return value.quantize(decimal.Decimal(".%s" % ("0" * self.precision)), rounding=self.rounding) |         return value.quantize(decimal.Decimal(".%s" % ("0" * self.precision)), rounding=self.rounding) | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         if value is None: |         if value is None: | ||||||
|             return value |             return value | ||||||
|         if self.force_string: |         if self.force_string: | ||||||
| @@ -401,7 +401,7 @@ class DateTimeField(BaseField): | |||||||
|         if not isinstance(new_value, (datetime.datetime, datetime.date)): |         if not isinstance(new_value, (datetime.datetime, datetime.date)): | ||||||
|             self.error(u'cannot parse date "%s"' % value) |             self.error(u'cannot parse date "%s"' % value) | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         if value is None: |         if value is None: | ||||||
|             return value |             return value | ||||||
|         if isinstance(value, datetime.datetime): |         if isinstance(value, datetime.datetime): | ||||||
| @@ -524,7 +524,7 @@ class ComplexDateTimeField(StringField): | |||||||
|         except Exception: |         except Exception: | ||||||
|             return original_value |             return original_value | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         value = self.to_python(value) |         value = self.to_python(value) | ||||||
|         return self._convert_from_datetime(value) |         return self._convert_from_datetime(value) | ||||||
|  |  | ||||||
| @@ -559,10 +559,10 @@ class EmbeddedDocumentField(BaseField): | |||||||
|             return self.document_type._from_son(value, _auto_dereference=self._auto_dereference) |             return self.document_type._from_son(value, _auto_dereference=self._auto_dereference) | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value, use_db_field=True, fields=None): | ||||||
|         if not isinstance(value, self.document_type): |         if not isinstance(value, self.document_type): | ||||||
|             return value |             return value | ||||||
|         return self.document_type.to_mongo(value, **kwargs) |         return self.document_type.to_mongo(value, use_db_field, fields) | ||||||
|  |  | ||||||
|     def validate(self, value, clean=True): |     def validate(self, value, clean=True): | ||||||
|         """Make sure that the document instance is an instance of the |         """Make sure that the document instance is an instance of the | ||||||
| @@ -612,11 +612,11 @@ class GenericEmbeddedDocumentField(BaseField): | |||||||
|  |  | ||||||
|         value.validate(clean=clean) |         value.validate(clean=clean) | ||||||
|  |  | ||||||
|     def to_mongo(self, document, **kwargs): |     def to_mongo(self, document, use_db_field=True, fields=None): | ||||||
|         if document is None: |         if document is None: | ||||||
|             return None |             return None | ||||||
|  |  | ||||||
|         data = document.to_mongo(**kwargs) |         data = document.to_mongo(use_db_field, fields) | ||||||
|         if '_cls' not in data: |         if '_cls' not in data: | ||||||
|             data['_cls'] = document._class_name |             data['_cls'] = document._class_name | ||||||
|         return data |         return data | ||||||
| @@ -628,7 +628,7 @@ class DynamicField(BaseField): | |||||||
|  |  | ||||||
|     Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data""" |     Used by :class:`~mongoengine.DynamicDocument` to handle dynamic data""" | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value, use_db_field=True, fields=None): | ||||||
|         """Convert a Python type to a MongoDB compatible type. |         """Convert a Python type to a MongoDB compatible type. | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
| @@ -637,7 +637,7 @@ class DynamicField(BaseField): | |||||||
|  |  | ||||||
|         if hasattr(value, 'to_mongo'): |         if hasattr(value, 'to_mongo'): | ||||||
|             cls = value.__class__ |             cls = value.__class__ | ||||||
|             val = value.to_mongo(**kwargs) |             val = value.to_mongo(use_db_field, fields) | ||||||
|             # If we its a document thats not inherited add _cls |             # If we its a document thats not inherited add _cls | ||||||
|             if isinstance(value, Document): |             if isinstance(value, Document): | ||||||
|                 val = {"_ref": value.to_dbref(), "_cls": cls.__name__} |                 val = {"_ref": value.to_dbref(), "_cls": cls.__name__} | ||||||
| @@ -655,7 +655,7 @@ class DynamicField(BaseField): | |||||||
|  |  | ||||||
|         data = {} |         data = {} | ||||||
|         for k, v in value.iteritems(): |         for k, v in value.iteritems(): | ||||||
|             data[k] = self.to_mongo(v, **kwargs) |             data[k] = self.to_mongo(v, use_db_field, fields) | ||||||
|  |  | ||||||
|         value = data |         value = data | ||||||
|         if is_list:  # Convert back to a list |         if is_list:  # Convert back to a list | ||||||
| @@ -767,8 +767,8 @@ class SortedListField(ListField): | |||||||
|             self._order_reverse = kwargs.pop('reverse') |             self._order_reverse = kwargs.pop('reverse') | ||||||
|         super(SortedListField, self).__init__(field, **kwargs) |         super(SortedListField, self).__init__(field, **kwargs) | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value, use_db_field=True, fields=None): | ||||||
|         value = super(SortedListField, self).to_mongo(value, **kwargs) |         value = super(SortedListField, self).to_mongo(value, use_db_field, fields) | ||||||
|         if self._ordering is not None: |         if self._ordering is not None: | ||||||
|             return sorted(value, key=itemgetter(self._ordering), |             return sorted(value, key=itemgetter(self._ordering), | ||||||
|                           reverse=self._order_reverse) |                           reverse=self._order_reverse) | ||||||
| @@ -954,7 +954,7 @@ class ReferenceField(BaseField): | |||||||
|  |  | ||||||
|         return super(ReferenceField, self).__get__(instance, owner) |         return super(ReferenceField, self).__get__(instance, owner) | ||||||
|  |  | ||||||
|     def to_mongo(self, document, **kwargs): |     def to_mongo(self, document): | ||||||
|         if isinstance(document, DBRef): |         if isinstance(document, DBRef): | ||||||
|             if not self.dbref: |             if not self.dbref: | ||||||
|                 return document.id |                 return document.id | ||||||
| @@ -977,7 +977,7 @@ class ReferenceField(BaseField): | |||||||
|         id_field_name = cls._meta['id_field'] |         id_field_name = cls._meta['id_field'] | ||||||
|         id_field = cls._fields[id_field_name] |         id_field = cls._fields[id_field_name] | ||||||
|  |  | ||||||
|         id_ = id_field.to_mongo(id_, **kwargs) |         id_ = id_field.to_mongo(id_) | ||||||
|         if self.document_type._meta.get('abstract'): |         if self.document_type._meta.get('abstract'): | ||||||
|             collection = cls._get_collection_name() |             collection = cls._get_collection_name() | ||||||
|             return DBRef(collection, id_, cls=cls._class_name) |             return DBRef(collection, id_, cls=cls._class_name) | ||||||
| @@ -1100,7 +1100,7 @@ class CachedReferenceField(BaseField): | |||||||
|  |  | ||||||
|         return super(CachedReferenceField, self).__get__(instance, owner) |         return super(CachedReferenceField, self).__get__(instance, owner) | ||||||
|  |  | ||||||
|     def to_mongo(self, document, **kwargs): |     def to_mongo(self, document, use_db_field=True, fields=None): | ||||||
|         id_field_name = self.document_type._meta['id_field'] |         id_field_name = self.document_type._meta['id_field'] | ||||||
|         id_field = self.document_type._fields[id_field_name] |         id_field = self.document_type._fields[id_field_name] | ||||||
|  |  | ||||||
| @@ -1115,11 +1115,15 @@ class CachedReferenceField(BaseField): | |||||||
|             # TODO: should raise here or will fail next statement |             # TODO: should raise here or will fail next statement | ||||||
|  |  | ||||||
|         value = SON(( |         value = SON(( | ||||||
|             ("_id", id_field.to_mongo(id_, **kwargs)), |             ("_id", id_field.to_mongo(id_)), | ||||||
|         )) |         )) | ||||||
|  |  | ||||||
|         kwargs['fields'] = self.fields |         if fields: | ||||||
|         value.update(dict(document.to_mongo(**kwargs))) |             new_fields = [f for f in self.fields if f in fields] | ||||||
|  |         else: | ||||||
|  |             new_fields = self.fields | ||||||
|  |              | ||||||
|  |         value.update(dict(document.to_mongo(use_db_field, fields=new_fields))) | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def prepare_query_value(self, op, value): |     def prepare_query_value(self, op, value): | ||||||
| @@ -1235,7 +1239,7 @@ class GenericReferenceField(BaseField): | |||||||
|             doc = doc_cls._from_son(doc) |             doc = doc_cls._from_son(doc) | ||||||
|         return doc |         return doc | ||||||
|  |  | ||||||
|     def to_mongo(self, document, **kwargs): |     def to_mongo(self, document): | ||||||
|         if document is None: |         if document is None: | ||||||
|             return None |             return None | ||||||
|  |  | ||||||
| @@ -1254,7 +1258,7 @@ class GenericReferenceField(BaseField): | |||||||
|         else: |         else: | ||||||
|             id_ = document |             id_ = document | ||||||
|  |  | ||||||
|         id_ = id_field.to_mongo(id_, **kwargs) |         id_ = id_field.to_mongo(id_) | ||||||
|         collection = document._get_collection_name() |         collection = document._get_collection_name() | ||||||
|         ref = DBRef(collection, id_) |         ref = DBRef(collection, id_) | ||||||
|         return SON(( |         return SON(( | ||||||
| @@ -1283,7 +1287,7 @@ class BinaryField(BaseField): | |||||||
|             value = bin_type(value) |             value = bin_type(value) | ||||||
|         return super(BinaryField, self).__set__(instance, value) |         return super(BinaryField, self).__set__(instance, value) | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         return Binary(value) |         return Binary(value) | ||||||
|  |  | ||||||
|     def validate(self, value): |     def validate(self, value): | ||||||
| @@ -1508,7 +1512,7 @@ class FileField(BaseField): | |||||||
|                                 db_alias=db_alias, |                                 db_alias=db_alias, | ||||||
|                                 collection_name=collection_name) |                                 collection_name=collection_name) | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         # Store the GridFS file id in MongoDB |         # Store the GridFS file id in MongoDB | ||||||
|         if isinstance(value, self.proxy_class) and value.grid_id is not None: |         if isinstance(value, self.proxy_class) and value.grid_id is not None: | ||||||
|             return value.grid_id |             return value.grid_id | ||||||
| @@ -1858,7 +1862,7 @@ class UUIDField(BaseField): | |||||||
|                 return original_value |                 return original_value | ||||||
|         return value |         return value | ||||||
|  |  | ||||||
|     def to_mongo(self, value, **kwargs): |     def to_mongo(self, value): | ||||||
|         if not self._binary: |         if not self._binary: | ||||||
|             return unicode(value) |             return unicode(value) | ||||||
|         elif isinstance(value, basestring): |         elif isinstance(value, basestring): | ||||||
|   | |||||||
| @@ -3527,7 +3527,7 @@ class FieldTest(unittest.TestCase): | |||||||
|             def __init__(self, **kwargs): |             def __init__(self, **kwargs): | ||||||
|                 super(EnumField, self).__init__(**kwargs) |                 super(EnumField, self).__init__(**kwargs) | ||||||
|  |  | ||||||
|             def to_mongo(self, value, **kwargs): |             def to_mongo(self, value): | ||||||
|                 return value |                 return value | ||||||
|  |  | ||||||
|             def to_python(self, value): |             def to_python(self, value): | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user