summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-08-17 20:06:16 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-08-17 20:06:16 -0400
commit530d3f07e0c1e70e0f9b80d3b5986253e06dcaf2 (patch)
treefccbb61ff4f3d869a7475e42f095421d37f4c270 /lib/sqlalchemy/orm
parent2de7f94739ec1873e1dce48797e1e6f12044cf4c (diff)
downloadsqlalchemy-530d3f07e0c1e70e0f9b80d3b5986253e06dcaf2.tar.gz
- Fixed bug where attribute "set" events or columns with
``@validates`` would have events triggered within the flush process, when those columns were the targets of a "fetch and populate" operation, such as an autoincremented primary key, a Python side default, or a server-side default "eagerly" fetched via RETURNING. fixes #3167
Diffstat (limited to 'lib/sqlalchemy/orm')
-rw-r--r--lib/sqlalchemy/orm/mapper.py29
-rw-r--r--lib/sqlalchemy/orm/persistence.py12
2 files changed, 22 insertions, 19 deletions
diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py
index fc15769cd..1e1291857 100644
--- a/lib/sqlalchemy/orm/mapper.py
+++ b/lib/sqlalchemy/orm/mapper.py
@@ -1189,14 +1189,6 @@ class Mapper(InspectionAttr):
util.ordered_column_set(t.c).\
intersection(all_cols)
- # determine cols that aren't expressed within our tables; mark these
- # as "read only" properties which are refreshed upon INSERT/UPDATE
- self._readonly_props = set(
- self._columntoproperty[col]
- for col in self._columntoproperty
- if not hasattr(col, 'table') or
- col.table not in self._cols_by_table)
-
# if explicit PK argument sent, add those columns to the
# primary key mappings
if self._primary_key_argument:
@@ -1247,6 +1239,15 @@ class Mapper(InspectionAttr):
self.primary_key = tuple(primary_key)
self._log("Identified primary key columns: %s", primary_key)
+ # determine cols that aren't expressed within our tables; mark these
+ # as "read only" properties which are refreshed upon INSERT/UPDATE
+ self._readonly_props = set(
+ self._columntoproperty[col]
+ for col in self._columntoproperty
+ if self._columntoproperty[col] not in self._primary_key_props and
+ (not hasattr(col, 'table') or
+ col.table not in self._cols_by_table))
+
def _configure_properties(self):
# Column and other ClauseElement objects which are mapped
@@ -2342,18 +2343,26 @@ class Mapper(InspectionAttr):
dict_ = state.dict
manager = state.manager
return [
- manager[self._columntoproperty[col].key].
+ manager[prop.key].
impl.get(state, dict_,
attributes.PASSIVE_RETURN_NEVER_SET)
- for col in self.primary_key
+ for prop in self._primary_key_props
]
+ @_memoized_configured_property
+ def _primary_key_props(self):
+ return [self._columntoproperty[col] for col in self.primary_key]
+
def _get_state_attr_by_column(
self, state, dict_, column,
passive=attributes.PASSIVE_RETURN_NEVER_SET):
prop = self._columntoproperty[column]
return state.manager[prop.key].impl.get(state, dict_, passive=passive)
+ def _set_committed_state_attr_by_column(self, state, dict_, column, value):
+ prop = self._columntoproperty[column]
+ state.manager[prop.key].impl.set_committed_value(state, dict_, value)
+
def _set_state_attr_by_column(self, state, dict_, column, value):
prop = self._columntoproperty[column]
state.manager[prop.key].impl.set(state, dict_, value, None)
diff --git a/lib/sqlalchemy/orm/persistence.py b/lib/sqlalchemy/orm/persistence.py
index 8c9b677fe..d511c0816 100644
--- a/lib/sqlalchemy/orm/persistence.py
+++ b/lib/sqlalchemy/orm/persistence.py
@@ -645,13 +645,7 @@ def _emit_insert_statements(base_mapper, uowtransaction,
mapper._pks_by_table[table]):
prop = mapper_rec._columntoproperty[col]
if state_dict.get(prop.key) is None:
- # TODO: would rather say:
- # state_dict[prop.key] = pk
- mapper_rec._set_state_attr_by_column(
- state,
- state_dict,
- col, pk)
-
+ state_dict[prop.key] = pk
_postfetch(
mapper_rec,
uowtransaction,
@@ -836,11 +830,11 @@ def _postfetch(mapper, uowtransaction, table,
for col in returning_cols:
if col.primary_key:
continue
- mapper._set_state_attr_by_column(state, dict_, col, row[col])
+ dict_[mapper._columntoproperty[col].key] = row[col]
for c in prefetch_cols:
if c.key in params and c in mapper._columntoproperty:
- mapper._set_state_attr_by_column(state, dict_, c, params[c.key])
+ dict_[mapper._columntoproperty[c].key] = params[c.key]
if postfetch_cols:
state._expire_attributes(state.dict,