Cascading saves now default to off (#291)
This commit is contained in:
parent
c60ea40828
commit
fe62c3aacb
@ -4,6 +4,7 @@ Changelog
|
|||||||
|
|
||||||
Changes in 0.8.X
|
Changes in 0.8.X
|
||||||
================
|
================
|
||||||
|
- Cascading saves now default to off (#291)
|
||||||
- ReferenceField now store ObjectId's by default rather than DBRef (#290)
|
- ReferenceField now store ObjectId's by default rather than DBRef (#290)
|
||||||
- Added ImageField support for inline replacements (#86)
|
- Added ImageField support for inline replacements (#86)
|
||||||
- Added SequenceField.set_next_value(value) helper (#159)
|
- Added SequenceField.set_next_value(value) helper (#159)
|
||||||
|
@ -5,11 +5,21 @@ Upgrading
|
|||||||
0.7 to 0.8
|
0.7 to 0.8
|
||||||
**********
|
**********
|
||||||
|
|
||||||
Inheritance
|
There have been numerous backwards breaking changes in 0.8. The reasons for
|
||||||
===========
|
these are ensure that MongoEngine has sane defaults going forward and
|
||||||
|
performs the best it can out the box. Where possible there have been
|
||||||
|
FutureWarnings to help get you ready for the change, but that hasn't been
|
||||||
|
possible for the whole of the release.
|
||||||
|
|
||||||
|
.. warning:: Breaking changes - test upgrading on a test system before putting
|
||||||
|
live. There maybe multiple manual steps in migrating and these are best honed
|
||||||
|
on a staging / test system.
|
||||||
|
|
||||||
Data Model
|
Data Model
|
||||||
----------
|
==========
|
||||||
|
|
||||||
|
Inheritance
|
||||||
|
-----------
|
||||||
|
|
||||||
The inheritance model has changed, we no longer need to store an array of
|
The inheritance model has changed, we no longer need to store an array of
|
||||||
:attr:`types` with the model we can just use the classname in :attr:`_cls`.
|
:attr:`types` with the model we can just use the classname in :attr:`_cls`.
|
||||||
@ -105,6 +115,21 @@ eg::
|
|||||||
p._mark_as_dirty('friends')
|
p._mark_as_dirty('friends')
|
||||||
p.save()
|
p.save()
|
||||||
|
|
||||||
|
|
||||||
|
Cascading Saves
|
||||||
|
---------------
|
||||||
|
To improve performance document saves will no longer automatically cascade.
|
||||||
|
Any changes to a Documents references will either have to be saved manually or
|
||||||
|
you will have to explicitly tell it to cascade on save::
|
||||||
|
|
||||||
|
# At the class level:
|
||||||
|
class Person(Document):
|
||||||
|
meta = {'cascade': True}
|
||||||
|
|
||||||
|
# Or on save:
|
||||||
|
my_document.save(cascade=True)
|
||||||
|
|
||||||
|
|
||||||
Querysets
|
Querysets
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
@ -244,7 +244,6 @@ class Document(BaseDocument):
|
|||||||
upsert=upsert, **write_concern)
|
upsert=upsert, **write_concern)
|
||||||
created = is_new_object(last_error)
|
created = is_new_object(last_error)
|
||||||
|
|
||||||
warn_cascade = not cascade and 'cascade' not in self._meta
|
|
||||||
cascade = (self._meta.get('cascade', True)
|
cascade = (self._meta.get('cascade', True)
|
||||||
if cascade is None else cascade)
|
if cascade is None else cascade)
|
||||||
if cascade:
|
if cascade:
|
||||||
@ -257,7 +256,7 @@ class Document(BaseDocument):
|
|||||||
if cascade_kwargs: # Allow granular control over cascades
|
if cascade_kwargs: # Allow granular control over cascades
|
||||||
kwargs.update(cascade_kwargs)
|
kwargs.update(cascade_kwargs)
|
||||||
kwargs['_refs'] = _refs
|
kwargs['_refs'] = _refs
|
||||||
self.cascade_save(warn_cascade=warn_cascade, **kwargs)
|
self.cascade_save(**kwargs)
|
||||||
|
|
||||||
except pymongo.errors.OperationFailure, err:
|
except pymongo.errors.OperationFailure, err:
|
||||||
message = 'Could not save document (%s)'
|
message = 'Could not save document (%s)'
|
||||||
@ -276,7 +275,7 @@ class Document(BaseDocument):
|
|||||||
signals.post_save.send(self.__class__, document=self, created=created)
|
signals.post_save.send(self.__class__, document=self, created=created)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def cascade_save(self, warn_cascade=None, *args, **kwargs):
|
def cascade_save(self, *args, **kwargs):
|
||||||
"""Recursively saves any references /
|
"""Recursively saves any references /
|
||||||
generic references on an objects"""
|
generic references on an objects"""
|
||||||
import fields
|
import fields
|
||||||
@ -296,10 +295,6 @@ class Document(BaseDocument):
|
|||||||
|
|
||||||
ref_id = "%s,%s" % (ref.__class__.__name__, str(ref._data))
|
ref_id = "%s,%s" % (ref.__class__.__name__, str(ref._data))
|
||||||
if ref and ref_id not in _refs:
|
if ref and ref_id not in _refs:
|
||||||
if warn_cascade:
|
|
||||||
msg = ("Cascading saves will default to off in 0.8, "
|
|
||||||
"please explicitly set `.save(cascade=True)`")
|
|
||||||
warnings.warn(msg, FutureWarning)
|
|
||||||
_refs.append(ref_id)
|
_refs.append(ref_id)
|
||||||
kwargs["_refs"] = _refs
|
kwargs["_refs"] = _refs
|
||||||
ref.save(**kwargs)
|
ref.save(**kwargs)
|
||||||
|
@ -17,7 +17,7 @@ __all__ = ('AllWarnings', )
|
|||||||
class AllWarnings(unittest.TestCase):
|
class AllWarnings(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
conn = connect(db='mongoenginetest')
|
connect(db='mongoenginetest')
|
||||||
self.warning_list = []
|
self.warning_list = []
|
||||||
self.showwarning_default = warnings.showwarning
|
self.showwarning_default = warnings.showwarning
|
||||||
warnings.showwarning = self.append_to_warning_list
|
warnings.showwarning = self.append_to_warning_list
|
||||||
@ -30,31 +30,6 @@ class AllWarnings(unittest.TestCase):
|
|||||||
# restore default handling of warnings
|
# restore default handling of warnings
|
||||||
warnings.showwarning = self.showwarning_default
|
warnings.showwarning = self.showwarning_default
|
||||||
|
|
||||||
def test_document_save_cascade_future_warning(self):
|
|
||||||
|
|
||||||
class Person(Document):
|
|
||||||
name = StringField()
|
|
||||||
parent = ReferenceField('self')
|
|
||||||
|
|
||||||
Person.drop_collection()
|
|
||||||
|
|
||||||
p1 = Person(name="Wilson Snr")
|
|
||||||
p1.parent = None
|
|
||||||
p1.save()
|
|
||||||
|
|
||||||
p2 = Person(name="Wilson Jr")
|
|
||||||
p2.parent = p1
|
|
||||||
p2.parent.name = "Poppa Wilson"
|
|
||||||
p2.save()
|
|
||||||
|
|
||||||
self.assertTrue(len(self.warning_list) > 0)
|
|
||||||
if len(self.warning_list) > 1:
|
|
||||||
print self.warning_list
|
|
||||||
warning = self.warning_list[0]
|
|
||||||
self.assertEqual(FutureWarning, warning["category"])
|
|
||||||
self.assertTrue("Cascading saves will default to off in 0.8"
|
|
||||||
in str(warning["message"]))
|
|
||||||
|
|
||||||
def test_document_collection_syntax_warning(self):
|
def test_document_collection_syntax_warning(self):
|
||||||
|
|
||||||
class NonAbstractBase(Document):
|
class NonAbstractBase(Document):
|
||||||
@ -67,6 +42,3 @@ class AllWarnings(unittest.TestCase):
|
|||||||
self.assertEqual(SyntaxWarning, warning["category"])
|
self.assertEqual(SyntaxWarning, warning["category"])
|
||||||
self.assertEqual('non_abstract_base',
|
self.assertEqual('non_abstract_base',
|
||||||
InheritedDocumentFailTest._get_collection_name())
|
InheritedDocumentFailTest._get_collection_name())
|
||||||
|
|
||||||
import sys
|
|
||||||
sys.path[0:0] = [""]
|
|
||||||
|
@ -678,7 +678,7 @@ class InstanceTest(unittest.TestCase):
|
|||||||
p1.reload()
|
p1.reload()
|
||||||
self.assertEqual(p1.name, p.parent.name)
|
self.assertEqual(p1.name, p.parent.name)
|
||||||
|
|
||||||
def test_save_cascade_meta(self):
|
def test_save_cascade_meta_false(self):
|
||||||
|
|
||||||
class Person(Document):
|
class Person(Document):
|
||||||
name = StringField()
|
name = StringField()
|
||||||
@ -707,6 +707,31 @@ class InstanceTest(unittest.TestCase):
|
|||||||
p1.reload()
|
p1.reload()
|
||||||
self.assertEqual(p1.name, p.parent.name)
|
self.assertEqual(p1.name, p.parent.name)
|
||||||
|
|
||||||
|
def test_save_cascade_meta_true(self):
|
||||||
|
|
||||||
|
class Person(Document):
|
||||||
|
name = StringField()
|
||||||
|
parent = ReferenceField('self')
|
||||||
|
|
||||||
|
meta = {'cascade': False}
|
||||||
|
|
||||||
|
Person.drop_collection()
|
||||||
|
|
||||||
|
p1 = Person(name="Wilson Snr")
|
||||||
|
p1.parent = None
|
||||||
|
p1.save()
|
||||||
|
|
||||||
|
p2 = Person(name="Wilson Jr")
|
||||||
|
p2.parent = p1
|
||||||
|
p2.save(cascade=True)
|
||||||
|
|
||||||
|
p = Person.objects(name="Wilson Jr").get()
|
||||||
|
p.parent.name = "Daddy Wilson"
|
||||||
|
p.save()
|
||||||
|
|
||||||
|
p1.reload()
|
||||||
|
self.assertNotEqual(p1.name, p.parent.name)
|
||||||
|
|
||||||
def test_save_cascades_generically(self):
|
def test_save_cascades_generically(self):
|
||||||
|
|
||||||
class Person(Document):
|
class Person(Document):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user