diff options
Diffstat (limited to 'lib/sqlalchemy/orm/dynamic.py')
-rw-r--r-- | lib/sqlalchemy/orm/dynamic.py | 79 |
1 files changed, 40 insertions, 39 deletions
diff --git a/lib/sqlalchemy/orm/dynamic.py b/lib/sqlalchemy/orm/dynamic.py index aa5105150..1b91bd977 100644 --- a/lib/sqlalchemy/orm/dynamic.py +++ b/lib/sqlalchemy/orm/dynamic.py @@ -6,32 +6,30 @@ from sqlalchemy.orm import attributes, object_session from sqlalchemy.orm.query import Query from sqlalchemy.orm.mapper import has_identity, object_mapper -class DynamicCollectionAttribute(attributes.InstrumentedAttribute): +class DynamicAttributeImpl(attributes.AttributeImpl): def __init__(self, class_, attribute_manager, key, typecallable, target_mapper, **kwargs): - super(DynamicCollectionAttribute, self).__init__(class_, attribute_manager, key, typecallable, **kwargs) + super(DynamicAttributeImpl, self).__init__(class_, attribute_manager, key, typecallable, **kwargs) self.target_mapper = target_mapper - def get(self, obj, passive=False): + def get(self, state, passive=False): if passive: - return self.get_history(obj, passive=True).added_items() + return self.get_history(state, passive=True).added_items() else: - return AppenderQuery(self, obj) + return AppenderQuery(self, state) - def commit_to_state(self, state, obj, value=attributes.NO_VALUE): + def commit_to_state(self, state, value=attributes.NO_VALUE): # we have our own AttributeHistory therefore dont need CommittedState # instead, we reset the history stored on the attribute - obj.__dict__[self.key] = CollectionHistory(self, obj) + state.dict[self.key] = CollectionHistory(self, state) - def get_collection(self, obj, user_data=None): - return self.get_history(obj)._added_items + def get_collection(self, state, user_data=None): + return self.get_history(state)._added_items - def set(self, obj, value, initiator): + def set(self, state, value, initiator): if initiator is self: return - state = obj._state - - old_collection = self.get(obj).assign(value) + old_collection = self.get(state).assign(value) # TODO: emit events ??? state.modified = True @@ -39,35 +37,36 @@ class DynamicCollectionAttribute(attributes.InstrumentedAttribute): def delete(self, *args, **kwargs): raise NotImplementedError() - def get_history(self, obj, passive=False): + def get_history(self, state, passive=False): try: - return obj.__dict__[self.key] + return state.dict[self.key] except KeyError: - obj.__dict__[self.key] = c = CollectionHistory(self, obj) + state.dict[self.key] = c = CollectionHistory(self, state) return c - def append(self, obj, value, initiator): + def append(self, state, value, initiator): if initiator is not self: - self.get_history(obj)._added_items.append(value) - self.fire_append_event(obj, value, self) + self.get_history(state)._added_items.append(value) + self.fire_append_event(state, value, self) - def remove(self, obj, value, initiator): + def remove(self, state, value, initiator): if initiator is not self: - self.get_history(obj)._deleted_items.append(value) - self.fire_remove_event(obj, value, self) + self.get_history(state)._deleted_items.append(value) + self.fire_remove_event(state, value, self) class AppenderQuery(Query): - def __init__(self, attr, instance): + def __init__(self, attr, state): super(AppenderQuery, self).__init__(attr.target_mapper, None) - self.instance = instance + self.state = state self.attr = attr def __session(self): - sess = object_session(self.instance) - if sess is not None and self.instance in sess and sess.autoflush: + instance = self.state.obj() + sess = object_session(instance) + if sess is not None and instance in sess and sess.autoflush: sess.flush() - if not has_identity(self.instance): + if not has_identity(instance): return None else: return sess @@ -75,21 +74,21 @@ class AppenderQuery(Query): def __len__(self): sess = self.__session() if sess is None: - return len(self.attr.get_history(self.instance)._added_items) + return len(self.attr.get_history(self.state)._added_items) else: return self._clone(sess).count() def __iter__(self): sess = self.__session() if sess is None: - return iter(self.attr.get_history(self.instance)._added_items) + return iter(self.attr.get_history(self.state)._added_items) else: return iter(self._clone(sess)) def __getitem__(self, index): sess = self.__session() if sess is None: - return self.attr.get_history(self.instance)._added_items.__getitem__(index) + return self.attr.get_history(self.state)._added_items.__getitem__(index) else: return self._clone(sess).__getitem__(index) @@ -97,39 +96,41 @@ class AppenderQuery(Query): # note we're returning an entirely new Query class instance here # without any assignment capabilities; # the class of this query is determined by the session. + instance = self.state.obj() if sess is None: - sess = object_session(self.instance) + sess = object_session(instance) if sess is None: try: - sess = object_mapper(self.instance).get_session() + sess = object_mapper(instance).get_session() except exceptions.InvalidRequestError: raise exceptions.InvalidRequestError("Parent instance %s is not bound to a Session, and no contextual session is established; lazy load operation of attribute '%s' cannot proceed" % (self.instance.__class__, self.key)) - return sess.query(self.attr.target_mapper).with_parent(self.instance) + return sess.query(self.attr.target_mapper).with_parent(instance) def assign(self, collection): - if has_identity(self.instance): + instance = self.state.obj() + if has_identity(instance): oldlist = list(self) else: oldlist = [] - self.attr.get_history(self.instance).replace(oldlist, collection) + self.attr.get_history(self.state).replace(oldlist, collection) return oldlist def append(self, item): - self.attr.append(self.instance, item, None) + self.attr.append(self.state, item, None) def remove(self, item): - self.attr.remove(self.instance, item, None) + self.attr.remove(self.state, item, None) class CollectionHistory(attributes.AttributeHistory): """Overrides AttributeHistory to receive append/remove events directly.""" - def __init__(self, attr, obj): + def __init__(self, attr, state): self._deleted_items = [] self._added_items = [] self._unchanged_items = [] - self._obj = obj + self._state = state def replace(self, olditems, newitems): self._added_items = newitems |