From 7451244cd27f83a82c4a3e65a767679f15c4af5e Mon Sep 17 00:00:00 2001 From: Ross Lawley Date: Thu, 6 Jun 2013 21:04:54 +0000 Subject: [PATCH] Fixed cascading saves which weren't turned off as planned (#291) --- docs/changelog.rst | 1 + mongoengine/base/metaclasses.py | 8 -------- mongoengine/document.py | 18 ++++++++++------- tests/document/instance.py | 36 +++++++++------------------------ 4 files changed, 22 insertions(+), 41 deletions(-) diff --git a/docs/changelog.rst b/docs/changelog.rst index c35cd9cb..a0468476 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,6 +5,7 @@ Changelog Changes in 0.8.2 ================ +- Fixed cascading saves which weren't turned off as planned (#291) - Fixed Datastructures so instances are a Document or EmbeddedDocument (#363) - Improved cascading saves write performance (#361) - Fixed amibiguity and differing behaviour regarding field defaults (#349) diff --git a/mongoengine/base/metaclasses.py b/mongoengine/base/metaclasses.py index 651228da..444d9a25 100644 --- a/mongoengine/base/metaclasses.py +++ b/mongoengine/base/metaclasses.py @@ -97,14 +97,6 @@ class DocumentMetaclass(type): attrs['_reverse_db_field_map'] = dict( (v, k) for k, v in attrs['_db_field_map'].iteritems()) - # Set cascade flag if not set - if 'cascade' not in attrs['_meta']: - ReferenceField = _import_class('ReferenceField') - GenericReferenceField = _import_class('GenericReferenceField') - cascade = any([isinstance(x, (ReferenceField, GenericReferenceField)) - for x in doc_fields.values()]) - attrs['_meta']['cascade'] = cascade - # # Set document hierarchy # diff --git a/mongoengine/document.py b/mongoengine/document.py index 2bdecb77..8b152d5e 100644 --- a/mongoengine/document.py +++ b/mongoengine/document.py @@ -186,8 +186,8 @@ class Document(BaseDocument): will force an fsync on the primary server. :param cascade: Sets the flag for cascading saves. You can set a default by setting "cascade" in the document __meta__ - :param cascade_kwargs: optional kwargs dictionary to be passed throw - to cascading saves + :param cascade_kwargs: (optional) kwargs dictionary to be passed throw + to cascading saves. Implies ``cascade=True``. :param _refs: A list of processed references used in cascading saves .. versionchanged:: 0.5 @@ -196,11 +196,13 @@ class Document(BaseDocument): :class:`~bson.dbref.DBRef` objects that have changes are saved as well. .. versionchanged:: 0.6 - Cascade saves are optional = defaults to True, if you want + Added cascading saves + .. versionchanged:: 0.8 + Cascade saves are optional and default to False. If you want fine grain control then you can turn off using document - meta['cascade'] = False Also you can pass different kwargs to + meta['cascade'] = True. Also you can pass different kwargs to the cascade save using cascade_kwargs which overwrites the - existing kwargs with custom values + existing kwargs with custom values. """ signals.pre_save.send(self.__class__, document=self) @@ -251,8 +253,10 @@ class Document(BaseDocument): upsert=True, **write_concern) created = is_new_object(last_error) - cascade = (self._meta.get('cascade', True) - if cascade is None else cascade) + + if cascade is None: + cascade = self._meta.get('cascade', False) or cascade_kwargs is not None + if cascade: kwargs = { "force_insert": force_insert, diff --git a/tests/document/instance.py b/tests/document/instance.py index 35338ab3..81734aa0 100644 --- a/tests/document/instance.py +++ b/tests/document/instance.py @@ -647,22 +647,6 @@ class InstanceTest(unittest.TestCase): self.assertEqual(b.picture, b.bar.picture, b.bar.bar.picture) - def test_setting_cascade(self): - - class ForcedCascade(Document): - meta = {'cascade': True} - - class Feed(Document): - name = StringField() - - class Subscription(Document): - name = StringField() - feed = ReferenceField(Feed) - - self.assertTrue(ForcedCascade._meta['cascade']) - self.assertTrue(Subscription._meta['cascade']) - self.assertFalse(Feed._meta['cascade']) - def test_save_cascades(self): class Person(Document): @@ -681,7 +665,7 @@ class InstanceTest(unittest.TestCase): p = Person.objects(name="Wilson Jr").get() p.parent.name = "Daddy Wilson" - p.save() + p.save(cascade=True) p1.reload() self.assertEqual(p1.name, p.parent.name) @@ -700,14 +684,12 @@ class InstanceTest(unittest.TestCase): p2 = Person(name="Wilson Jr") p2.parent = p1 + p1.name = "Daddy Wilson" p2.save(force_insert=True, cascade_kwargs={"force_insert": False}) - p = Person.objects(name="Wilson Jr").get() - p.parent.name = "Daddy Wilson" - p.save() - p1.reload() - self.assertEqual(p1.name, p.parent.name) + p2.reload() + self.assertEqual(p1.name, p2.parent.name) def test_save_cascade_meta_false(self): @@ -782,6 +764,10 @@ class InstanceTest(unittest.TestCase): p.parent.name = "Daddy Wilson" p.save() + p1.reload() + self.assertNotEqual(p1.name, p.parent.name) + + p.save(cascade=True) p1.reload() self.assertEqual(p1.name, p.parent.name) @@ -1057,8 +1043,6 @@ class InstanceTest(unittest.TestCase): Feed.drop_collection() UserSubscription.drop_collection() - self.assertTrue(UserSubscription._meta['cascade']) - o1 = Organization(name="o1").save() o2 = Organization(name="o2").save() @@ -1090,7 +1074,7 @@ class InstanceTest(unittest.TestCase): self.assertEqual(q, 1) sub.user.name = "Test" self.assertEqual(q, 2) - sub.save() + sub.save(cascade=True) self.assertEqual(q, 3) # Changing a value and one that will cascade @@ -1101,7 +1085,7 @@ class InstanceTest(unittest.TestCase): self.assertEqual(q, 1) sub.user.name = "Test 2" self.assertEqual(q, 2) - sub.save() + sub.save(cascade=True) self.assertEqual(q, 4) # One for the UserSub and one for the User # Saving with just the refs