summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/orm/attributes.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-12-17 14:19:22 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2010-12-17 14:19:22 -0500
commit2e7a54d6fbfe9260887a0eb848e296e3b5e59c47 (patch)
tree66b121a8a3a984e676acf47997ac119878d7ccd1 /lib/sqlalchemy/orm/attributes.py
parentb5f3648188ee46e7c0353d3123f8ed6d55f31b56 (diff)
parentba964522e15da9062f5ed11e8bf55a0b5fb54693 (diff)
downloadsqlalchemy-2e7a54d6fbfe9260887a0eb848e296e3b5e59c47.tar.gz
merge tip
Diffstat (limited to 'lib/sqlalchemy/orm/attributes.py')
-rw-r--r--lib/sqlalchemy/orm/attributes.py72
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.
"""