Fixed cascading saves which weren't turned off as planned (#291)

This commit is contained in:
Ross Lawley 2013-06-06 21:04:54 +00:00
parent d935b5764a
commit 7451244cd2
4 changed files with 22 additions and 41 deletions

View File

@ -5,6 +5,7 @@ Changelog
Changes in 0.8.2 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) - Fixed Datastructures so instances are a Document or EmbeddedDocument (#363)
- Improved cascading saves write performance (#361) - Improved cascading saves write performance (#361)
- Fixed amibiguity and differing behaviour regarding field defaults (#349) - Fixed amibiguity and differing behaviour regarding field defaults (#349)

View File

@ -97,14 +97,6 @@ class DocumentMetaclass(type):
attrs['_reverse_db_field_map'] = dict( attrs['_reverse_db_field_map'] = dict(
(v, k) for k, v in attrs['_db_field_map'].iteritems()) (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 # Set document hierarchy
# #

View File

@ -186,8 +186,8 @@ class Document(BaseDocument):
will force an fsync on the primary server. will force an fsync on the primary server.
:param cascade: Sets the flag for cascading saves. You can set a :param cascade: Sets the flag for cascading saves. You can set a
default by setting "cascade" in the document __meta__ default by setting "cascade" in the document __meta__
:param cascade_kwargs: optional kwargs dictionary to be passed throw :param cascade_kwargs: (optional) kwargs dictionary to be passed throw
to cascading saves to cascading saves. Implies ``cascade=True``.
:param _refs: A list of processed references used in cascading saves :param _refs: A list of processed references used in cascading saves
.. versionchanged:: 0.5 .. versionchanged:: 0.5
@ -196,11 +196,13 @@ class Document(BaseDocument):
:class:`~bson.dbref.DBRef` objects that have changes are :class:`~bson.dbref.DBRef` objects that have changes are
saved as well. saved as well.
.. versionchanged:: 0.6 .. 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 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 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) signals.pre_save.send(self.__class__, document=self)
@ -251,8 +253,10 @@ class Document(BaseDocument):
upsert=True, **write_concern) upsert=True, **write_concern)
created = is_new_object(last_error) 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: if cascade:
kwargs = { kwargs = {
"force_insert": force_insert, "force_insert": force_insert,

View File

@ -647,22 +647,6 @@ class InstanceTest(unittest.TestCase):
self.assertEqual(b.picture, b.bar.picture, b.bar.bar.picture) 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): def test_save_cascades(self):
class Person(Document): class Person(Document):
@ -681,7 +665,7 @@ class InstanceTest(unittest.TestCase):
p = Person.objects(name="Wilson Jr").get() p = Person.objects(name="Wilson Jr").get()
p.parent.name = "Daddy Wilson" p.parent.name = "Daddy Wilson"
p.save() p.save(cascade=True)
p1.reload() p1.reload()
self.assertEqual(p1.name, p.parent.name) self.assertEqual(p1.name, p.parent.name)
@ -700,14 +684,12 @@ class InstanceTest(unittest.TestCase):
p2 = Person(name="Wilson Jr") p2 = Person(name="Wilson Jr")
p2.parent = p1 p2.parent = p1
p1.name = "Daddy Wilson"
p2.save(force_insert=True, cascade_kwargs={"force_insert": False}) 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() 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): def test_save_cascade_meta_false(self):
@ -782,6 +764,10 @@ class InstanceTest(unittest.TestCase):
p.parent.name = "Daddy Wilson" p.parent.name = "Daddy Wilson"
p.save() p.save()
p1.reload()
self.assertNotEqual(p1.name, p.parent.name)
p.save(cascade=True)
p1.reload() p1.reload()
self.assertEqual(p1.name, p.parent.name) self.assertEqual(p1.name, p.parent.name)
@ -1057,8 +1043,6 @@ class InstanceTest(unittest.TestCase):
Feed.drop_collection() Feed.drop_collection()
UserSubscription.drop_collection() UserSubscription.drop_collection()
self.assertTrue(UserSubscription._meta['cascade'])
o1 = Organization(name="o1").save() o1 = Organization(name="o1").save()
o2 = Organization(name="o2").save() o2 = Organization(name="o2").save()
@ -1090,7 +1074,7 @@ class InstanceTest(unittest.TestCase):
self.assertEqual(q, 1) self.assertEqual(q, 1)
sub.user.name = "Test" sub.user.name = "Test"
self.assertEqual(q, 2) self.assertEqual(q, 2)
sub.save() sub.save(cascade=True)
self.assertEqual(q, 3) self.assertEqual(q, 3)
# Changing a value and one that will cascade # Changing a value and one that will cascade
@ -1101,7 +1085,7 @@ class InstanceTest(unittest.TestCase):
self.assertEqual(q, 1) self.assertEqual(q, 1)
sub.user.name = "Test 2" sub.user.name = "Test 2"
self.assertEqual(q, 2) self.assertEqual(q, 2)
sub.save() sub.save(cascade=True)
self.assertEqual(q, 4) # One for the UserSub and one for the User self.assertEqual(q, 4) # One for the UserSub and one for the User
# Saving with just the refs # Saving with just the refs