From 63c5a4dd65498e3ff150b3bc12dc053f1d402b4a Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Tue, 22 Nov 2011 07:34:08 -0800 Subject: [PATCH] Fixes saving document schemas that have changed Ensures that form defaults which are documents are automatically marked as changed, so schemas can evolve without migration issues. [#360] --- AUTHORS | 1 + docs/changelog.rst | 1 + mongoengine/base.py | 9 ++++++++- tests/document.py | 30 ++++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 4f68be2f..573ddb11 100644 --- a/AUTHORS +++ b/AUTHORS @@ -74,4 +74,5 @@ that much better: * Marc Tamlyn * Karim Allah * Adam Parrish + * jpfarias diff --git a/docs/changelog.rst b/docs/changelog.rst index 53943127..6ce81e5b 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,7 @@ Changelog Changes in dev ============== +- Fixed document mutation saving issue - Fixed positional operator when replacing embedded documents - Added Non-Django Style choices back (you can have either) - Fixed __repr__ of a sliced queryset diff --git a/mongoengine/base.py b/mongoengine/base.py index b021eac7..4198e8b2 100644 --- a/mongoengine/base.py +++ b/mongoengine/base.py @@ -883,14 +883,21 @@ class BaseDocument(object): """.strip() % class_name) cls = subclasses[class_name] + changed_fields = [] for field_name, field in cls._fields.items(): if field.db_field in data: value = data[field.db_field] data[field_name] = (value if value is None else field.to_python(value)) + elif field.default: + default = field.default + if callable(default): + default = default() + if isinstance(default, BaseDocument): + changed_fields.append(field_name) obj = cls(**data) - obj._changed_fields = [] + obj._changed_fields = changed_fields return obj def _mark_as_changed(self, key): diff --git a/tests/document.py b/tests/document.py index 816bb498..9da886c1 100644 --- a/tests/document.py +++ b/tests/document.py @@ -2360,6 +2360,36 @@ class DocumentTest(unittest.TestCase): self.assertRaises(InvalidDocumentError, throw_invalid_document_error) + def test_mutating_documents(self): + + class B(EmbeddedDocument): + field1 = StringField(default='field1') + + class A(Document): + b = EmbeddedDocumentField(B, default=lambda: B()) + + A.drop_collection() + a = A() + a.save() + a.reload() + self.assertEquals(a.b.field1, 'field1') + + class C(EmbeddedDocument): + c_field = StringField(default='cfield') + + class B(EmbeddedDocument): + field1 = StringField(default='field1') + field2 = EmbeddedDocumentField(C, default=lambda: C()) + + class A(Document): + b = EmbeddedDocumentField(B, default=lambda: B()) + + a = A.objects()[0] + a.b.field2.c_field = 'new value' + a.save() + + a.reload() + self.assertEquals(a.b.field2.c_field, 'new value') if __name__ == '__main__': unittest.main()