diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-04-20 17:38:03 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-04-20 17:38:03 -0400 |
commit | a3af638e1a95d42075e25e87474663348dcf5c14 (patch) | |
tree | 4549f2261067856a251367d49e97e40d0bb84b2c /lib/sqlalchemy/orm/relationships.py | |
parent | bd61e7a3287079cf742f4df698bfe3628c090522 (diff) | |
download | sqlalchemy-a3af638e1a95d42075e25e87474663348dcf5c14.tar.gz |
- Fixed more regressions caused by NEVER_SET; comparisons
to transient objects with attributes unset would leak NEVER_SET,
and negated_contains_or_equals would do so for any transient
object as the comparison used only the committed value.
Repaired the NEVER_SET cases, fixes #3371, and also made
negated_contains_or_equals() use state_attr_by_column() just
like a non-negated comparison, fixes #3374
Diffstat (limited to 'lib/sqlalchemy/orm/relationships.py')
-rw-r--r-- | lib/sqlalchemy/orm/relationships.py | 47 |
1 files changed, 33 insertions, 14 deletions
diff --git a/lib/sqlalchemy/orm/relationships.py b/lib/sqlalchemy/orm/relationships.py index b649c9e21..d1c5e5e51 100644 --- a/lib/sqlalchemy/orm/relationships.py +++ b/lib/sqlalchemy/orm/relationships.py @@ -1233,11 +1233,15 @@ class RelationshipProperty(StrategizedProperty): state = attributes.instance_state(other) def state_bindparam(x, state, col): - o = state.obj() # strong ref + dict_ = state.dict return sql.bindparam( - x, unique=True, callable_=lambda: - self.property.mapper. - _get_committed_attr_by_column(o, col)) + x, unique=True, + callable_=self.property._get_attr_w_warn_on_none( + col, + self.property.mapper._get_state_attr_by_column, + state, dict_, col, passive=attributes.PASSIVE_OFF + ) + ) def adapt(col): if self.adapter: @@ -1252,13 +1256,14 @@ class RelationshipProperty(StrategizedProperty): adapt(x) == None) for (x, y) in self.property.local_remote_pairs]) - criterion = sql.and_(*[x == y for (x, y) in - zip( - self.property.mapper.primary_key, - self.property. - mapper. - primary_key_from_instance(other)) + criterion = sql.and_(*[ + x == y for (x, y) in + zip( + self.property.mapper.primary_key, + self.property.mapper.primary_key_from_instance(other) + ) ]) + return ~self._criterion_exists(criterion) def __ne__(self, other): @@ -1357,10 +1362,12 @@ class RelationshipProperty(StrategizedProperty): def visit_bindparam(bindparam): if bindparam._identifying_key in bind_to_col: - bindparam.callable = \ - lambda: mapper._get_state_attr_by_column( - state, dict_, - bind_to_col[bindparam._identifying_key]) + bindparam.callable = self._get_attr_w_warn_on_none( + bind_to_col[bindparam._identifying_key], + mapper._get_state_attr_by_column, + state, dict_, + bind_to_col[bindparam._identifying_key], + passive=attributes.PASSIVE_OFF) if self.secondary is not None and alias_secondary: criterion = ClauseAdapter( @@ -1374,6 +1381,18 @@ class RelationshipProperty(StrategizedProperty): criterion = adapt_source(criterion) return criterion + def _get_attr_w_warn_on_none(self, column, fn, *arg, **kw): + def _go(): + value = fn(*arg, **kw) + if value is None: + util.warn( + "Got None for value of column %s; this is unsupported " + "for a relationship comparison and will not " + "currently produce an IS comparison " + "(but may in a future release)" % column) + return value + return _go + def _lazy_none_clause(self, reverse_direction=False, adapt_source=None): if not reverse_direction: criterion, bind_to_col = \ |