diff options
| author | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-03-02 20:27:53 -0500 |
|---|---|---|
| committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2013-03-02 20:27:53 -0500 |
| commit | b83dd4dc2200bece2896a125be6d4f0911669d15 (patch) | |
| tree | 32f4b23b870d6d4b92142b50481a9b838bebcfd0 /lib/sqlalchemy/orm/properties.py | |
| parent | 98fea3e3dca48071c213d9f039195f9421ed200a (diff) | |
| download | sqlalchemy-b83dd4dc2200bece2896a125be6d4f0911669d15.tar.gz | |
Can set/change the "cascade" attribute on a :func:`.relationship`
construct after it's been constructed already. This is not
a pattern for normal use but we like to change the setting
for demonstration purposes in tutorials.
Diffstat (limited to 'lib/sqlalchemy/orm/properties.py')
| -rw-r--r-- | lib/sqlalchemy/orm/properties.py | 84 |
1 files changed, 51 insertions, 33 deletions
diff --git a/lib/sqlalchemy/orm/properties.py b/lib/sqlalchemy/orm/properties.py index c618e89b2..a0d8c92d1 100644 --- a/lib/sqlalchemy/orm/properties.py +++ b/lib/sqlalchemy/orm/properties.py @@ -230,6 +230,8 @@ class RelationshipProperty(StrategizedProperty): strategy_wildcard_key = 'relationship:*' + _dependency_processor = None + def __init__(self, argument, secondary=None, primaryjoin=None, secondaryjoin=None, @@ -252,7 +254,7 @@ class RelationshipProperty(StrategizedProperty): load_on_pending=False, strategy_class=None, _local_remote_pairs=None, query_class=None, - info=None): + info=None): self.uselist = uselist self.argument = argument @@ -297,17 +299,8 @@ class RelationshipProperty(StrategizedProperty): self._reverse_property = set() - if cascade is not False: - self.cascade = CascadeOptions(cascade) - else: - self.cascade = CascadeOptions("save-update, merge") - - if self.passive_deletes == 'all' and \ - ("delete" in self.cascade or - "delete-orphan" in self.cascade): - raise sa_exc.ArgumentError( - "Can't set passive_deletes='all' in conjunction " - "with 'delete' or 'delete-orphan' cascade") + self.cascade = cascade if cascade is not False \ + else "save-update, merge" self.order_by = order_by @@ -723,8 +716,8 @@ class RelationshipProperty(StrategizedProperty): if self.property._use_get: return sql.and_(*[ sql.or_( - adapt(x) != state_bindparam(adapt(x), state, y), - adapt(x) == None) + adapt(x) != state_bindparam(adapt(x), state, y), + adapt(x) == None) for (x, y) in self.property.local_remote_pairs]) criterion = sql.and_(*[x == y for (x, y) in @@ -838,7 +831,7 @@ class RelationshipProperty(StrategizedProperty): if (source_state, r) in _recursive: return - if not "merge" in self.cascade: + if not "merge" in self._cascade: return if self.key not in source_dict: @@ -916,7 +909,7 @@ class RelationshipProperty(StrategizedProperty): def cascade_iterator(self, type_, state, dict_, visited_states, halt_on=None): - #assert type_ in self.cascade + #assert type_ in self._cascade # only actively lazy load on the 'delete' cascade if type_ != 'delete' or self.passive_deletes: @@ -933,7 +926,7 @@ class RelationshipProperty(StrategizedProperty): passive=passive) skip_pending = type_ == 'refresh-expire' and 'delete-orphan' \ - not in self.cascade + not in self._cascade for instance_state, c in tuples: if instance_state in visited_states: @@ -980,7 +973,7 @@ class RelationshipProperty(StrategizedProperty): 'does not reference mapper %s' % (key, self, other, self.parent)) if self.direction in (ONETOMANY, MANYTOONE) and self.direction \ - == other.direction: + == other.direction: raise sa_exc.ArgumentError('%s and back-reference %s are ' 'both of the same direction %r. Did you mean to ' 'set remote_side on the many-to-one side ?' @@ -1025,7 +1018,7 @@ class RelationshipProperty(StrategizedProperty): self._check_conflicts() self._process_dependent_arguments() self._setup_join_conditions() - self._check_cascade_settings() + self._check_cascade_settings(self._cascade) self._post_init() self._generate_backref() super(RelationshipProperty, self).do_init() @@ -1043,7 +1036,7 @@ class RelationshipProperty(StrategizedProperty): for attr in ( 'order_by', 'primaryjoin', 'secondaryjoin', 'secondary', '_user_defined_foreign_keys', 'remote_side', - ): + ): attr_value = getattr(self, attr) if util.callable(attr_value): setattr(self, attr, attr_value()) @@ -1080,10 +1073,6 @@ class RelationshipProperty(StrategizedProperty): self.target = self.mapper.mapped_table - if self.cascade.delete_orphan: - self.mapper.primary_mapper()._delete_orphans.append( - (self.key, self.parent.class_) - ) def _setup_join_conditions(self): self._join_condition = jc = relationships.JoinCondition( @@ -1134,29 +1123,58 @@ class RelationshipProperty(StrategizedProperty): if not self.parent.concrete: for inheriting in self.parent.iterate_to_root(): if inheriting is not self.parent \ - and inheriting.has_property(self.key): + and inheriting.has_property(self.key): util.warn("Warning: relationship '%s' on mapper " "'%s' supersedes the same relationship " "on inherited mapper '%s'; this can " "cause dependency issues during flush" % (self.key, self.parent, inheriting)) - def _check_cascade_settings(self): - if self.cascade.delete_orphan and not self.single_parent \ + @property + def cascade(self): + """Return the current cascade setting for this + :class:`.RelationshipProperty`. + """ + return self._cascade + + @cascade.setter + def cascade(self, cascade): + cascade = CascadeOptions(cascade) + if 'mapper' in self.__dict__: + self._check_cascade_settings(cascade) + self._cascade = cascade + + if self._dependency_processor: + self._dependency_processor.cascade = cascade + + def _check_cascade_settings(self, cascade): + if cascade.delete_orphan and not self.single_parent \ and (self.direction is MANYTOMANY or self.direction is MANYTOONE): raise sa_exc.ArgumentError( 'On %s, delete-orphan cascade is not supported ' - 'on a many-to-many or many-to-one relationship ' - 'when single_parent is not set. Set ' - 'single_parent=True on the relationship().' - % self) + 'on a many-to-many or many-to-one relationship ' + 'when single_parent is not set. Set ' + 'single_parent=True on the relationship().' + % self) if self.direction is MANYTOONE and self.passive_deletes: util.warn("On %s, 'passive_deletes' is normally configured " "on one-to-many, one-to-one, many-to-many " "relationships only." % self) + if self.passive_deletes == 'all' and \ + ("delete" in cascade or + "delete-orphan" in cascade): + raise sa_exc.ArgumentError( + "On %s, can't set passive_deletes='all' in conjunction " + "with 'delete' or 'delete-orphan' cascade" % self) + + if cascade.delete_orphan: + self.mapper.primary_mapper()._delete_orphans.append( + (self.key, self.parent.class_) + ) + def _columns_are_mapped(self, *cols): """Return True if all columns in the given collection are mapped by the tables referenced by this :class:`.Relationship`. @@ -1164,10 +1182,10 @@ class RelationshipProperty(StrategizedProperty): """ for c in cols: if self.secondary is not None \ - and self.secondary.c.contains_column(c): + and self.secondary.c.contains_column(c): continue if not self.parent.mapped_table.c.contains_column(c) and \ - not self.target.c.contains_column(c): + not self.target.c.contains_column(c): return False return True |
