summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/relationships.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-04-20 17:38:03 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-04-20 17:38:03 -0400
commita3af638e1a95d42075e25e87474663348dcf5c14 (patch)
tree4549f2261067856a251367d49e97e40d0bb84b2c /lib/sqlalchemy/orm/relationships.py
parentbd61e7a3287079cf742f4df698bfe3628c090522 (diff)
downloadsqlalchemy-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.py47
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 = \