From 556e620c7a5b4cff3f9b93ce0361b39033e587f9 Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Fri, 1 Jul 2011 08:44:46 +0100 Subject: [PATCH] Fixes recursion error when resetting changed fields Fixes #214 - thanks to wpjunior for the test case --- mongoengine/document.py | 9 ++++++--- tests/document.py | 26 ++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/mongoengine/document.py b/mongoengine/document.py index 31a2530c..c653c8fb 100644 --- a/mongoengine/document.py +++ b/mongoengine/document.py @@ -162,15 +162,18 @@ class Document(BaseDocument): id_field = self._meta['id_field'] self[id_field] = self._fields[id_field].to_python(object_id) - def reset_changed_fields(doc): + def reset_changed_fields(doc, inspected_docs=None): """Loop through and reset changed fields lists""" + + inspected_docs = inspected_docs or [] + inspected_docs.append(doc) if hasattr(doc, '_changed_fields'): doc._changed_fields = [] for field_name in doc._fields: field = getattr(doc, field_name) - if hasattr(field, '_changed_fields') and field != doc: - reset_changed_fields(field) + if field not in inspected_docs and hasattr(field, '_changed_fields'): + reset_changed_fields(field, inspected_docs) reset_changed_fields(self) signals.post_save.send(self.__class__, document=self, created=created) diff --git a/tests/document.py b/tests/document.py index c1abd463..9498cfb2 100644 --- a/tests/document.py +++ b/tests/document.py @@ -1045,6 +1045,32 @@ class DocumentTest(unittest.TestCase): except ValidationError: self.fail() + def test_save_max_recursion_not_hit(self): + + class Person(Document): + name = StringField() + parent = ReferenceField('self') + friend = ReferenceField('self') + + Person.drop_collection() + + p1 = Person(name="Wilson Jr") + p1.parent = None + p1.save() + + p2 = Person(name="Wilson Jr2") + p2.parent = p1 + p2.save() + + p1.friend = p2 + p1.save() + + # Confirm can save and it resets the changed fields without hitting + # max recursion error + p0 = Person.objects.first() + p0.name = 'wpjunior' + p0.save() + def test_update(self): """Ensure that an existing document is updated instead of be overwritten. """