Compare commits

...

2 Commits

Author SHA1 Message Date
Stefan Wojcik
a659f9aa8d Add a changelog entry [ci skip] 2019-06-21 15:59:04 +02:00
Stefan Wojcik
f884839d17 Implement BaseDocument.to_dict
`BaseDocument.to_dict` serializes a document/embedded document into a dict,
which can be easily consumed by other modules (which in this case don't need
to be aware of MongoEngine-specific object types).

The output dict contains key-value pairs where:
* Keys are field names as they're defined on the document (as opposed to e.g.
  how they're stored in MongoDB).
* Values are field values in their deserialized form (i.e. the same form that
  you get when you access `doc.some_field_name`).
2019-06-21 15:45:33 +02:00
3 changed files with 103 additions and 9 deletions

View File

@ -6,6 +6,7 @@ Changelog
Development
===========
- (Fill this out as you fix issues and develop your features).
- Add a `BaseDocument.to_dict` method #2101
Changes in 0.18.1
=================

View File

@ -309,9 +309,7 @@ class BaseDocument(object):
return self._data['_text_score']
def to_mongo(self, use_db_field=True, fields=None):
"""
Return as SON data ready for use with MongoDB.
"""
"""Return as SON data ready for use with MongoDB."""
fields = fields or []
data = SON()
@ -412,12 +410,35 @@ class BaseDocument(object):
message = 'ValidationError (%s:%s) ' % (self._class_name, pk)
raise ValidationError(message, errors=errors)
def to_dict(self):
"""Serialize this document into a dict.
Return field names as they're defined on the document (as opposed to
e.g. how they're stored in MongoDB). Return values in their
deserialized form (i.e. the same form that you get when you access
`doc.some_field_name`). Serialize embedded documents recursively.
The resultant dict can be consumed easily by other modules which
don't need to be aware of MongoEngine-specific object types.
:return dict: dictionary of field name & value pairs.
"""
data_dict = {}
for field_name in self._fields:
value = getattr(self, field_name)
if isinstance(value, BaseDocument):
data_dict[field_name] = value.to_dict()
else:
data_dict[field_name] = value
return data_dict
def to_json(self, *args, **kwargs):
"""Convert this document to JSON.
:param use_db_field: Serialize field names as they appear in
MongoDB (as opposed to attribute names on this document).
Defaults to True.
:return str: string representing the jsonified document.
"""
use_db_field = kwargs.pop('use_db_field', True)
return json_util.dumps(self.to_mongo(use_db_field), *args, **kwargs)
@ -426,12 +447,13 @@ class BaseDocument(object):
def from_json(cls, json_data, created=False):
"""Converts json data to a Document instance
:param json_data: The json data to load into the Document
:param created: If True, the document will be considered as a brand new document
If False and an id is provided, it will consider that the data being
loaded corresponds to what's already in the database (This has an impact of subsequent call to .save())
If False and no id is provided, it will consider the data as a new document
(default ``False``)
:param str json_data: The json data to load into the Document
:param bool created: If True, the document will be considered as
a brand new document. If False and an ID is provided, it will
consider that the data being loaded corresponds to what's already
in the database (This has an impact of subsequent call to .save())
If False and no id is provided, it will consider the data as a new
document (default ``False``)
"""
return cls._from_son(json_util.loads(json_data), created=created)

View File

@ -3525,5 +3525,76 @@ class InstanceTest(MongoDBTestCase):
User.objects().select_related()
class DocumentToDictTest(MongoDBTestCase):
"""Class for testing the BaseDocument.to_dict method."""
def test_to_dict(self):
class Person(Document):
name = StringField()
age = IntField()
p = Person(name='Tom', age=30)
self.assertEqual(p.to_dict(), {'id': None, 'name': 'Tom', 'age': 30})
def test_to_dict_with_a_persisted_doc(self):
class Person(Document):
name = StringField()
age = IntField()
p = Person.objects.create(name='Tom', age=30)
p_dict = p.to_dict()
self.assertTrue(p_dict['id'])
self.assertEqual(p_dict['name'], 'Tom')
self.assertEqual(p_dict['age'], 30)
def test_to_dict_empty_doc(self):
class Person(Document):
name = StringField()
age = IntField()
p = Person()
self.assertEqual(p.to_dict(), {'id': None, 'name': None, 'age': None})
def test_to_dict_with_default_values(self):
class Person(Document):
name = StringField(default='Unknown')
age = IntField(default=0)
p = Person()
self.assertEqual(
p.to_dict(),
{'id': None, 'name': 'Unknown', 'age': 0}
)
def test_to_dict_with_a_db_field(self):
class Person(Document):
name = StringField(db_field='db_name')
p = Person(name='Tom')
self.assertEqual(p.to_dict(), {'id': None, 'name': 'Tom'})
def test_to_dict_with_a_primary_key(self):
class Person(Document):
username = StringField(primary_key=True)
p = Person(username='tomtom')
self.assertEqual(p.to_dict(), {'username': 'tomtom'})
def test_to_dict_with_an_embedded_document(self):
class Book(EmbeddedDocument):
title = StringField()
class Author(Document):
name = StringField()
book = EmbeddedDocumentField(Book)
a = Author(name='Yuval', book=Book(title='Sapiens'))
self.assertEqual(a.to_dict(), {
'id': None,
'name': 'Yuval',
'book': {'title': 'Sapiens'}
})
if __name__ == '__main__':
unittest.main()