Merge pull request #697 from nleite/master

to_json not resolving db_fields #654
This commit is contained in:
Yohan Graterol 2014-07-07 17:39:34 -05:00
commit f6220cab3b
5 changed files with 52 additions and 19 deletions

View File

@ -205,3 +205,4 @@ that much better:
* Aleksandr Sorokoumov (https://github.com/Gerrrr) * Aleksandr Sorokoumov (https://github.com/Gerrrr)
* Clay McClure (https://github.com/claymation) * Clay McClure (https://github.com/claymation)
* Bruno Rocha (https://github.com/rochacbruno) * Bruno Rocha (https://github.com/rochacbruno)
* Norberto Leite (https://github.com/nleite)

View File

@ -5,7 +5,7 @@ Changelog
Changes in 0.9.X - DEV Changes in 0.9.X - DEV
====================== ======================
- Added support to show original model fields on to_json calls instead of db_field #697
- Fixed tests for Django 1.7 #696 - Fixed tests for Django 1.7 #696
- Follow ReferenceFields in EmbeddedDocuments with select_related #690 - Follow ReferenceFields in EmbeddedDocuments with select_related #690
- Added preliminary support for text indexes #680 - Added preliminary support for text indexes #680

View File

@ -257,7 +257,7 @@ class BaseDocument(object):
""" """
pass pass
def to_mongo(self): def to_mongo(self, use_db_field=True):
"""Return as SON data ready for use with MongoDB. """Return as SON data ready for use with MongoDB.
""" """
data = SON() data = SON()
@ -271,7 +271,11 @@ 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:
value = field.to_mongo(value) EmbeddedDocument = _import_class("EmbeddedDocument")
if isinstance(value, (EmbeddedDocument)) and use_db_field==False:
value = field.to_mongo(value, use_db_field)
else:
value = field.to_mongo(value)
# Handle self generating fields # Handle self generating fields
if value is None and field._auto_gen: if value is None and field._auto_gen:
@ -279,7 +283,10 @@ class BaseDocument(object):
self._data[field_name] = value self._data[field_name] = value
if value is not None: if value is not None:
data[field.db_field] = value if use_db_field:
data[field.db_field] = value
else:
data[field.name] = value
# If "_id" has not been set, then try and set it # If "_id" has not been set, then try and set it
Document = _import_class("Document") Document = _import_class("Document")
@ -342,8 +349,11 @@ class BaseDocument(object):
raise ValidationError(message, errors=errors) raise ValidationError(message, errors=errors)
def to_json(self, *args, **kwargs): def to_json(self, *args, **kwargs):
"""Converts a document to JSON""" """Converts a document to JSON.
return json_util.dumps(self.to_mongo(), *args, **kwargs) :param use_db_field: Set to True by default but enables the output of the json structure with the field names and not the mongodb store db_names in case of set to False
"""
use_db_field = kwargs.pop('use_db_field') if kwargs.has_key('use_db_field') else True
return json_util.dumps(self.to_mongo(use_db_field), *args, **kwargs)
@classmethod @classmethod
def from_json(cls, json_data): def from_json(cls, json_data):

View File

@ -311,7 +311,7 @@ class DecimalField(BaseField):
return value return value
return value.quantize(self.precision, rounding=self.rounding) return value.quantize(self.precision, rounding=self.rounding)
def to_mongo(self, value): def to_mongo(self, value, use_db_field=True):
if value is None: if value is None:
return value return value
if self.force_string: if self.force_string:
@ -551,10 +551,10 @@ class EmbeddedDocumentField(BaseField):
return self.document_type._from_son(value) return self.document_type._from_son(value)
return value return value
def to_mongo(self, value): def to_mongo(self, value, use_db_field=True):
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) return self.document_type.to_mongo(value, use_db_field)
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
@ -601,11 +601,11 @@ class GenericEmbeddedDocumentField(BaseField):
value.validate(clean=clean) value.validate(clean=clean)
def to_mongo(self, document): def to_mongo(self, document, use_db_field=True):
if document is None: if document is None:
return None return None
data = document.to_mongo() data = document.to_mongo(use_db_field)
if not '_cls' in data: if not '_cls' in data:
data['_cls'] = document._class_name data['_cls'] = document._class_name
return data return data
@ -628,7 +628,7 @@ class DynamicField(BaseField):
cls = value.__class__ cls = value.__class__
val = value.to_mongo() val = value.to_mongo()
# 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__}
if (isinstance(value, EmbeddedDocument)): if (isinstance(value, EmbeddedDocument)):
val['_cls'] = cls.__name__ val['_cls'] = cls.__name__
@ -1001,7 +1001,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): def to_mongo(self, document, use_db_field=True):
if document is None: if document is None:
return None return None
@ -1567,7 +1567,7 @@ class SequenceField(BaseField):
def prepare_query_value(self, op, value): def prepare_query_value(self, op, value):
""" """
This method is overriden in order to convert the query value into to required This method is overriden in order to convert the query value into to required
type. We need to do this in order to be able to successfully compare query type. We need to do this in order to be able to successfully compare query
values passed as string, the base implementation returns the value as is. values passed as string, the base implementation returns the value as is.
""" """
return self.value_decorator(value) return self.value_decorator(value)
@ -1631,12 +1631,12 @@ class UUIDField(BaseField):
class GeoPointField(BaseField): class GeoPointField(BaseField):
"""A list storing a longitude and latitude coordinate. """A list storing a longitude and latitude coordinate.
.. note:: this represents a generic point in a 2D plane and a legacy way of .. note:: this represents a generic point in a 2D plane and a legacy way of
representing a geo point. It admits 2d indexes but not "2dsphere" indexes representing a geo point. It admits 2d indexes but not "2dsphere" indexes
in MongoDB > 2.4 which are more natural for modeling geospatial points. in MongoDB > 2.4 which are more natural for modeling geospatial points.
See :ref:`geospatial-indexes` See :ref:`geospatial-indexes`
.. versionadded:: 0.4 .. versionadded:: 0.4
""" """

View File

@ -20,6 +20,28 @@ class TestJson(unittest.TestCase):
def setUp(self): def setUp(self):
connect(db='mongoenginetest') connect(db='mongoenginetest')
def test_json_names(self):
"""
Going to test reported issue:
https://github.com/MongoEngine/mongoengine/issues/654
where the reporter asks for the availability to perform
a to_json with the original class names and not the abreviated
mongodb document keys
"""
class Embedded(EmbeddedDocument):
string = StringField(db_field='s')
class Doc(Document):
string = StringField(db_field='s')
embedded = EmbeddedDocumentField(Embedded, db_field='e')
doc = Doc( string="Hello", embedded=Embedded(string="Inner Hello"))
doc_json = doc.to_json(sort_keys=True, use_db_field=False,separators=(',', ':'))
expected_json = """{"embedded":{"string":"Inner Hello"},"string":"Hello"}"""
self.assertEqual( doc_json, expected_json)
def test_json_simple(self): def test_json_simple(self):
class Embedded(EmbeddedDocument): class Embedded(EmbeddedDocument):