diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-11-17 19:34:47 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-11-17 19:34:47 -0500 |
| commit | 1321a0c2b95ce4381157d0633f2d292a1d286151 (patch) | |
| tree | 90206e66436c6e79ead76b37a6cae476417329f4 /lib/sqlalchemy/orm/dependency.py | |
| parent | d3ca4156495af556e448a8d3f6d5884d08ab2f9b (diff) | |
| download | sqlalchemy-1321a0c2b95ce4381157d0633f2d292a1d286151.tar.gz | |
- establish a consistent pattern of behavior along o2m, m2m, and m2o relationships
when "save-update" cascade is disabled, or the target object is otherwise not
present in the session, and collection/scalar changes have taken place. A warning
is emitted describing the type of operation, the target reference, and the relationship
description, stating that the operation will not take place. The operation then doesn't
take place. [ticket:1973]
- clean up test_cascade a little bit, remove cruft
Diffstat (limited to 'lib/sqlalchemy/orm/dependency.py')
| -rw-r--r-- | lib/sqlalchemy/orm/dependency.py | 83 |
1 files changed, 59 insertions, 24 deletions
diff --git a/lib/sqlalchemy/orm/dependency.py b/lib/sqlalchemy/orm/dependency.py index 4458a8547..e57b1575a 100644 --- a/lib/sqlalchemy/orm/dependency.py +++ b/lib/sqlalchemy/orm/dependency.py @@ -405,7 +405,9 @@ class OneToManyDP(DependencyProcessor): if should_null_fks: for child in history.unchanged: if child is not None: - uowcommit.register_object(child) + uowcommit.register_object(child, + operation="delete", prop=self.prop) + def presort_saves(self, uowcommit, states): @@ -422,15 +424,20 @@ class OneToManyDP(DependencyProcessor): if history: for child in history.added: if child is not None: - uowcommit.register_object(child, cancel_delete=True) + uowcommit.register_object(child, cancel_delete=True, + operation="add", + prop=self.prop) children_added.update(history.added) for child in history.deleted: if not self.cascade.delete_orphan: - uowcommit.register_object(child, isdelete=False) + uowcommit.register_object(child, isdelete=False, + operation='delete', + prop=self.prop) elif self.hasparent(child) is False: - uowcommit.register_object(child, isdelete=True) + uowcommit.register_object(child, isdelete=True, + operation="delete", prop=self.prop) for c, m in self.mapper.cascade_iterator( 'delete', child): uowcommit.register_object( @@ -444,7 +451,9 @@ class OneToManyDP(DependencyProcessor): uowcommit.register_object( child, False, - self.passive_updates) + self.passive_updates, + operation="pk change", + prop=self.prop) def process_deletes(self, uowcommit, states): # head object is being deleted, and we manage its list of @@ -649,7 +658,8 @@ class ManyToOneDP(DependencyProcessor): for child in todelete: if child is None: continue - uowcommit.register_object(child, isdelete=True) + uowcommit.register_object(child, isdelete=True, + operation="delete", prop=self.prop) for c, m in self.mapper.cascade_iterator( 'delete', child): uowcommit.register_object( @@ -657,7 +667,7 @@ class ManyToOneDP(DependencyProcessor): def presort_saves(self, uowcommit, states): for state in states: - uowcommit.register_object(state) + uowcommit.register_object(state, operation="add", prop=self.prop) if self.cascade.delete_orphan: history = uowcommit.get_attribute_history( state, @@ -667,7 +677,9 @@ class ManyToOneDP(DependencyProcessor): ret = True for child in history.deleted: if self.hasparent(child) is False: - uowcommit.register_object(child, isdelete=True) + uowcommit.register_object(child, isdelete=True, + operation="delete", prop=self.prop) + for c, m in self.mapper.cascade_iterator( 'delete', child): uowcommit.register_object( @@ -699,17 +711,27 @@ class ManyToOneDP(DependencyProcessor): passive=True) if history: for child in history.added: - self._synchronize(state, child, None, False, uowcommit) + self._synchronize(state, child, None, False, + uowcommit, "add") if self.post_update: self._post_update(state, uowcommit, history.sum()) - def _synchronize(self, state, child, associationrow, - clearkeys, uowcommit): + def _synchronize(self, state, child, associationrow, + clearkeys, uowcommit, operation=None): if state is None or \ (not self.post_update and uowcommit.is_deleted(state)): return + if operation is not None and \ + child is not None and \ + not uowcommit.session._contains_state(child): + util.warn( + "Child %s not in session, %s " + "operation along '%s' won't proceed" % + (mapperutil.state_str(child), operation, self.prop)) + return + if clearkeys or child is None: sync.clear(state, self.parent, self.prop.synchronize_pairs) else: @@ -914,7 +936,8 @@ class ManyToManyDP(DependencyProcessor): if history: for child in history.deleted: if self.hasparent(child) is False: - uowcommit.register_object(child, isdelete=True) + uowcommit.register_object(child, isdelete=True, + operation="delete", prop=self.prop) for c, m in self.mapper.cascade_iterator( 'delete', child): @@ -939,15 +962,15 @@ class ManyToManyDP(DependencyProcessor): for child in history.non_added(): if child is None or \ (processed is not None and - (state, child) in processed) or \ - not uowcommit.session._contains_state(child): + (state, child) in processed): continue associationrow = {} - self._synchronize( + if not self._synchronize( state, child, associationrow, - False, uowcommit) + False, uowcommit, "delete"): + continue secondary_delete.append(associationrow) tmp.update((c, state) for c in history.non_added()) @@ -978,22 +1001,23 @@ class ManyToManyDP(DependencyProcessor): (state, child) in processed): continue associationrow = {} - self._synchronize(state, + if not self._synchronize(state, child, associationrow, - False, uowcommit) + False, uowcommit, "add"): + continue secondary_insert.append(associationrow) for child in history.deleted: if child is None or \ (processed is not None and - (state, child) in processed) or \ - not uowcommit.session._contains_state(child): + (state, child) in processed): continue associationrow = {} - self._synchronize(state, + if not self._synchronize(state, child, associationrow, - False, uowcommit) + False, uowcommit, "delete"): + continue secondary_delete.append(associationrow) tmp.update((c, state) @@ -1066,16 +1090,27 @@ class ManyToManyDP(DependencyProcessor): connection.execute(statement, secondary_insert) def _synchronize(self, state, child, associationrow, - clearkeys, uowcommit): + clearkeys, uowcommit, operation): if associationrow is None: return + + if child is not None and not uowcommit.session._contains_state(child): + if not child.deleted: + util.warn( + "Child %s not in session, %s " + "operation along '%s' won't proceed" % + (mapperutil.state_str(child), operation, self.prop)) + return False + self._verify_canload(child) sync.populate_dict(state, self.parent, associationrow, self.prop.synchronize_pairs) sync.populate_dict(child, self.mapper, associationrow, self.prop.secondary_synchronize_pairs) - + + return True + def _pks_changed(self, uowcommit, state): return sync.source_modified( uowcommit, |
