summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/dynamic.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2008-07-19 21:33:58 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2008-07-19 21:33:58 +0000
commita4781e4d76c6b1bfb8ae5345c2e09ae35045d8e6 (patch)
tree6fd8340944b3ccae2dff328c7f64d0f0c2ac4e55 /lib/sqlalchemy/orm/dynamic.py
parentd56862cbca1796edafab8845fd1852f6183512f8 (diff)
downloadsqlalchemy-a4781e4d76c6b1bfb8ae5345c2e09ae35045d8e6.tar.gz
- A critical fix to dynamic relations allows the
"modified" history to be properly cleared after a flush().
Diffstat (limited to 'lib/sqlalchemy/orm/dynamic.py')
-rw-r--r--lib/sqlalchemy/orm/dynamic.py54
1 files changed, 29 insertions, 25 deletions
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py
index 424ef85b7..3d139dff1 100644
--- a/lib/sqlalchemy/orm/dynamic.py
+++ b/lib/sqlalchemy/orm/dynamic.py
@@ -18,7 +18,7 @@ from sqlalchemy.orm import (
attributes, object_session, util as mapperutil, strategies,
)
from sqlalchemy.orm.query import Query
-from sqlalchemy.orm.util import has_identity
+from sqlalchemy.orm.util import _state_has_identity, has_identity
class DynaLoader(strategies.AbstractRelationLoader):
@@ -55,7 +55,8 @@ class DynamicAttributeImpl(attributes.AttributeImpl):
return history.added_items + history.unchanged_items
def fire_append_event(self, state, value, initiator):
- state.modified = True
+ collection_history = self._modified_event(state)
+ collection_history.added_items.append(value)
if self.trackparent and value is not None:
self.sethasparent(attributes.instance_state(value), True)
@@ -63,22 +64,36 @@ class DynamicAttributeImpl(attributes.AttributeImpl):
ext.append(state, value, initiator or self)
def fire_remove_event(self, state, value, initiator):
- state.modified = True
+ collection_history = self._modified_event(state)
+ collection_history.deleted_items.append(value)
if self.trackparent and value is not None:
self.sethasparent(attributes.instance_state(value), False)
for ext in self.extensions:
ext.remove(state, value, initiator or self)
+
+ def _modified_event(self, state):
+ state.modified = True
+ if self.key not in state.committed_state:
+ state.committed_state[self.key] = CollectionHistory(self, state)
+
+ # this is a hack to allow the _base.ComparableEntity fixture
+ # to work
+ state.dict[self.key] = True
+
+ return state.committed_state[self.key]
def set(self, state, value, initiator):
if initiator is self:
return
-
- old_collection = self.get(state).assign(value)
-
- # TODO: emit events ???
- state.modified = True
+
+ collection_history = self._modified_event(state)
+ if _state_has_identity(state):
+ old_collection = list(self.get(state))
+ else:
+ old_collection = []
+ collection_history.replace(old_collection, value)
def delete(self, *args, **kwargs):
raise NotImplementedError()
@@ -88,11 +103,11 @@ class DynamicAttributeImpl(attributes.AttributeImpl):
return (c.added_items, c.unchanged_items, c.deleted_items)
def _get_collection_history(self, state, passive=False):
- try:
- c = state.dict[self.key]
- except KeyError:
- state.dict[self.key] = c = CollectionHistory(self, state)
-
+ if self.key in state.committed_state:
+ c = state.committed_state[self.key]
+ else:
+ c = CollectionHistory(self, state)
+
if not passive:
return CollectionHistory(self, state, apply_to=c)
else:
@@ -100,15 +115,13 @@ class DynamicAttributeImpl(attributes.AttributeImpl):
def append(self, state, value, initiator, passive=False):
if initiator is not self:
- self._get_collection_history(state, passive=True).added_items.append(value)
self.fire_append_event(state, value, initiator)
def remove(self, state, value, initiator, passive=False):
if initiator is not self:
- self._get_collection_history(state, passive=True).deleted_items.append(value)
self.fire_remove_event(state, value, initiator)
-
+
class AppenderQuery(Query):
def __init__(self, attr, state):
super(AppenderQuery, self).__init__(attr.target_mapper, None)
@@ -170,15 +183,6 @@ class AppenderQuery(Query):
q = q.order_by(self.attr.order_by)
return q
- def assign(self, collection):
- instance = self.instance
- if has_identity(instance):
- oldlist = list(self)
- else:
- oldlist = []
- self.attr._get_collection_history(attributes.instance_state(self.instance), passive=True).replace(oldlist, collection)
- return oldlist
-
def append(self, item):
self.attr.append(attributes.instance_state(self.instance), item, None)