diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-12-17 14:19:22 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2010-12-17 14:19:22 -0500 |
commit | 2e7a54d6fbfe9260887a0eb848e296e3b5e59c47 (patch) | |
tree | 66b121a8a3a984e676acf47997ac119878d7ccd1 /lib/sqlalchemy/orm/attributes.py | |
parent | b5f3648188ee46e7c0353d3123f8ed6d55f31b56 (diff) | |
parent | ba964522e15da9062f5ed11e8bf55a0b5fb54693 (diff) | |
download | sqlalchemy-2e7a54d6fbfe9260887a0eb848e296e3b5e59c47.tar.gz |
merge tip
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 72 |
1 files changed, 44 insertions, 28 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 002215268..e7ab4c3a1 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -23,6 +23,7 @@ mapperutil = util.importlater("sqlalchemy.orm", "util") PASSIVE_NO_RESULT = util.symbol('PASSIVE_NO_RESULT') ATTR_WAS_SET = util.symbol('ATTR_WAS_SET') +ATTR_EMPTY = util.symbol('ATTR_EMPTY') NO_VALUE = util.symbol('NO_VALUE') NEVER_SET = util.symbol('NEVER_SET') @@ -59,7 +60,7 @@ class QueryableAttribute(interfaces.PropComparator): self.impl = impl self.comparator = comparator self.parententity = parententity - + manager = manager_of_class(class_) # manager is None in the case of AliasedClass if manager: @@ -72,6 +73,10 @@ class QueryableAttribute(interfaces.PropComparator): dispatch = event.dispatcher(events.AttributeEvents) dispatch.dispatch_cls.active_history = False + @util.memoized_property + def _supports_population(self): + return self.impl.supports_population + def get_history(self, instance, **kwargs): return self.impl.get_history(instance_state(instance), instance_dict(instance), **kwargs) @@ -127,8 +132,12 @@ class InstrumentedAttribute(QueryableAttribute): def __get__(self, instance, owner): if instance is None: return self - return self.impl.get(instance_state(instance), - instance_dict(instance)) + + dict_ = instance_dict(instance) + if self._supports_population and self.key in dict_: + return dict_[self.key] + else: + return self.impl.get(instance_state(instance),dict_) def create_proxied_attribute(descriptor): """Create an QueryableAttribute / user descriptor hybrid. @@ -324,33 +333,37 @@ class AttributeImpl(object): resulting value will be set as the new value for this attribute. """ - try: + if self.key in dict_: return dict_[self.key] - except KeyError: - # if no history, check for lazy callables, etc. - if state.committed_state.get(self.key, NEVER_SET) is NEVER_SET: + else: + # if history present, don't load + key = self.key + if key not in state.committed_state or \ + state.committed_state[key] is NEVER_SET: if passive is PASSIVE_NO_INITIALIZE: return PASSIVE_NO_RESULT - if self.key in state.callables: - callable_ = state.callables[self.key] - elif self.callable_ is not None: - callable_ = self.callable_(state) + if key in state.callables: + callable_ = state.callables[key] + value = callable_(passive) + elif self.callable_: + value = self.callable_(state, passive) else: - callable_ = None - - if callable_ is not None: - #if passive is not PASSIVE_OFF: - # return PASSIVE_NO_RESULT - value = callable_(passive=passive) - if value is PASSIVE_NO_RESULT: - return value - elif value is not ATTR_WAS_SET: - return self.set_committed_value(state, dict_, value) - else: - if self.key not in dict_: - return self.get(state, dict_, passive=passive) - return dict_[self.key] + value = ATTR_EMPTY + + if value is PASSIVE_NO_RESULT: + return value + elif value is ATTR_WAS_SET: + try: + return dict_[key] + except KeyError: + # TODO: no test coverage here. + raise KeyError( + "Deferred loader for attribute " + "%r failed to populate " + "correctly" % key) + elif value is not ATTR_EMPTY: + return self.set_committed_value(state, dict_, value) # Return a new, empty value return self.initialize(state, dict_) @@ -650,6 +663,7 @@ class CollectionAttributeImpl(AttributeImpl): if original is NO_VALUE: return list(current) else: + # TODO: use the dict() of state, obj here current_set = util.IdentitySet(current) original_set = util.IdentitySet(original) @@ -790,10 +804,8 @@ class CollectionAttributeImpl(AttributeImpl): collection, user_data = self._initialize_collection(state) if value: - for item in value: - collection.append_without_event(item) + collection.append_multiple_without_event(value) - state.callables.pop(self.key, None) state.dict[self.key] = user_data state.commit(dict_, [self.key]) @@ -1070,6 +1082,10 @@ def get_all_pending(state, dict_, key): state, key, passive=PASSIVE_NO_INITIALIZE).sum() + + TODO: we'd like to more closely merge the "history" tuple + generation with "get_all_pending()", making the presence + of the "History" object optional. """ |