Improve BaseDocument.from_json tests and documentation (#2127)

This commit is contained in:
Stefan Wójcik 2019-07-15 12:15:55 +02:00 committed by GitHub
parent d09af430e8
commit ac416aeeb3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 51 deletions

View File

@ -463,13 +463,21 @@ class BaseDocument(object):
def from_json(cls, json_data, created=False): def from_json(cls, json_data, created=False):
"""Converts json data to a Document instance """Converts json data to a Document instance
:param json_data: The json data to load into the Document :param str json_data: The json data to load into the Document
:param created: If True, the document will be considered as a brand new document :param bool created: Boolean defining whether to consider the newly
If False and an id is provided, it will consider that the data being instantiated document as brand new or as persisted already:
loaded corresponds to what's already in the database (This has an impact of subsequent call to .save()) * If True, consider the document as brand new, no matter what data
If False and no id is provided, it will consider the data as a new document it's loaded with (i.e. even if an ID is loaded).
(default ``False``) * If False and an ID is NOT provided, consider the document as
brand new.
* If False and an ID is provided, assume that the object has
already been persisted (this has an impact on the subsequent
call to .save()).
* Defaults to ``False``.
""" """
# TODO should `created` default to False? If the object already exists
# in the DB, you would likely retrieve it from MongoDB itself through
# a query, not load it from JSON data.
return cls._from_son(json_util.loads(json_data), created=created) return cls._from_son(json_util.loads(json_data), created=created)
def __expand_dynamic_values(self, name, value): def __expand_dynamic_values(self, name, value):

View File

@ -3429,83 +3429,114 @@ class InstanceTest(MongoDBTestCase):
self.assertEqual(Person.objects(height=189).count(), 1) self.assertEqual(Person.objects(height=189).count(), 1)
def test_from_son(self): def test_shard_key_mutability_after_from_json(self):
# 771 """Ensure that a document ID can be modified after from_json.
class MyPerson(self.Person):
meta = dict(shard_key=["id"])
p = MyPerson.from_json('{"name": "name", "age": 27}', created=True) If you instantiate a document by using from_json/_from_son and you
self.assertEqual(p.id, None) indicate that this should be considered a new document (vs a doc that
p.id = ( already exists in the database), then you should be able to modify
"12345" fields that are part of its shard key (note that this is not permitted
) # in case it is not working: "OperationError: Shard Keys are immutable..." will be raised here on docs that are already persisted).
p = MyPerson._from_son({"name": "name", "age": 27}, created=True)
self.assertEqual(p.id, None)
p.id = (
"12345"
) # in case it is not working: "OperationError: Shard Keys are immutable..." will be raised here
def test_from_son_created_False_without_id(self): See https://github.com/mongoengine/mongoengine/issues/771 for details.
class MyPerson(Document): """
class Person(Document):
name = StringField()
age = IntField()
meta = {"shard_key": ("id", "name")}
p = Person.from_json('{"name": "name", "age": 27}', created=True)
self.assertEqual(p._created, True)
p.name = "new name"
p.id = "12345"
self.assertEqual(p.name, "new name")
self.assertEqual(p.id, "12345")
def test_shard_key_mutability_after_from_son(self):
"""Ensure that a document ID can be modified after _from_son.
See `test_shard_key_mutability_after_from_json` above for more details.
"""
class Person(Document):
name = StringField()
age = IntField()
meta = {"shard_key": ("id", "name")}
p = Person._from_son({"name": "name", "age": 27}, created=True)
self.assertEqual(p._created, True)
p.name = "new name"
p.id = "12345"
self.assertEqual(p.name, "new name")
self.assertEqual(p.id, "12345")
def test_from_json_created_false_without_an_id(self):
class Person(Document):
name = StringField() name = StringField()
MyPerson.objects.delete() Person.objects.delete()
p = MyPerson.from_json('{"name": "a_fancy_name"}', created=False) p = Person.from_json('{"name": "name"}', created=False)
self.assertFalse(p._created) self.assertEqual(p._created, False)
self.assertIsNone(p.id) self.assertEqual(p.id, None)
# Make sure the document is subsequently persisted correctly.
p.save() p.save()
self.assertIsNotNone(p.id) self.assertTrue(p.id is not None)
saved_p = MyPerson.objects.get(id=p.id) saved_p = Person.objects.get(id=p.id)
self.assertEqual(saved_p.name, "a_fancy_name") self.assertEqual(saved_p.name, "name")
def test_from_son_created_False_with_id(self): def test_from_json_created_false_with_an_id(self):
# 1854 """See https://github.com/mongoengine/mongoengine/issues/1854"""
class MyPerson(Document):
class Person(Document):
name = StringField() name = StringField()
MyPerson.objects.delete() Person.objects.delete()
p = MyPerson.from_json( p = Person.from_json(
'{"_id": "5b85a8b04ec5dc2da388296e", "name": "a_fancy_name"}', created=False '{"_id": "5b85a8b04ec5dc2da388296e", "name": "name"}', created=False
) )
self.assertFalse(p._created) self.assertEqual(p._created, False)
self.assertEqual(p._changed_fields, []) self.assertEqual(p._changed_fields, [])
self.assertEqual(p.name, "a_fancy_name") self.assertEqual(p.name, "name")
self.assertEqual(p.id, ObjectId("5b85a8b04ec5dc2da388296e")) self.assertEqual(p.id, ObjectId("5b85a8b04ec5dc2da388296e"))
p.save() p.save()
with self.assertRaises(DoesNotExist): with self.assertRaises(DoesNotExist):
# Since created=False and we gave an id in the json and _changed_fields is empty # Since the object is considered as already persisted (thanks to
# mongoengine assumes that the document exits with that structure already # `created=False` and an existing ID), and we haven't changed any
# and calling .save() didn't save anything # fields (i.e. `_changed_fields` is empty), the document is
MyPerson.objects.get(id=p.id) # considered unchanged and hence the `save()` call above did
# nothing.
Person.objects.get(id=p.id)
self.assertFalse(p._created) self.assertFalse(p._created)
p.name = "a new fancy name" p.name = "a new name"
self.assertEqual(p._changed_fields, ["name"]) self.assertEqual(p._changed_fields, ["name"])
p.save() p.save()
saved_p = MyPerson.objects.get(id=p.id) saved_p = Person.objects.get(id=p.id)
self.assertEqual(saved_p.name, p.name) self.assertEqual(saved_p.name, p.name)
def test_from_son_created_True_with_an_id(self): def test_from_json_created_true_with_an_id(self):
class MyPerson(Document): class Person(Document):
name = StringField() name = StringField()
MyPerson.objects.delete() Person.objects.delete()
p = MyPerson.from_json( p = Person.from_json(
'{"_id": "5b85a8b04ec5dc2da388296e", "name": "a_fancy_name"}', created=True '{"_id": "5b85a8b04ec5dc2da388296e", "name": "name"}', created=True
) )
self.assertTrue(p._created) self.assertTrue(p._created)
self.assertEqual(p._changed_fields, []) self.assertEqual(p._changed_fields, [])
self.assertEqual(p.name, "a_fancy_name") self.assertEqual(p.name, "name")
self.assertEqual(p.id, ObjectId("5b85a8b04ec5dc2da388296e")) self.assertEqual(p.id, ObjectId("5b85a8b04ec5dc2da388296e"))
p.save() p.save()
saved_p = MyPerson.objects.get(id=p.id) saved_p = Person.objects.get(id=p.id)
self.assertEqual(saved_p, p) self.assertEqual(saved_p, p)
self.assertEqual(p.name, "a_fancy_name") self.assertEqual(saved_p.name, "name")
def test_null_field(self): def test_null_field(self):
# 734 # 734