diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/sqlalchemy/orm/attributes.py | 32 | ||||
| -rw-r--r-- | lib/sqlalchemy/sql/expression.py | 18 |
2 files changed, 29 insertions, 21 deletions
diff --git a/lib/sqlalchemy/orm/attributes.py b/lib/sqlalchemy/orm/attributes.py index 677167c1b..6d5fae507 100644 --- a/lib/sqlalchemy/orm/attributes.py +++ b/lib/sqlalchemy/orm/attributes.py @@ -208,20 +208,22 @@ class AttributeImpl(object): try: return state.dict[self.key] except KeyError: - callable_ = self._get_callable(state) - if callable_ is not None: - if passive: - return PASSIVE_NORESULT - value = callable_() - if value is not ATTR_WAS_SET: - return self.set_committed_value(state, value) - else: - if self.key not in state.dict: - return self.get(state, passive=passive) - return state.dict[self.key] - else: - # Return a new, empty value - return self.initialize(state) + # if no history, check for lazy callables, etc. + if self.key not in state.committed_state: + callable_ = self._get_callable(state) + if callable_ is not None: + if passive: + return PASSIVE_NORESULT + value = callable_() + if value is not ATTR_WAS_SET: + return self.set_committed_value(state, value) + else: + if self.key not in state.dict: + return self.get(state, passive=passive) + return state.dict[self.key] + + # Return a new, empty value + return self.initialize(state) def append(self, state, value, initiator, passive=False): self.set(state, value, initiator) @@ -767,9 +769,11 @@ class InstanceState(object): self.dict.pop(attr.impl.key, None) self.callables[attr.impl.key] = self.__fire_trigger self.expired_attributes.add(attr.impl.key) + self.committed_state = {} else: for key in attribute_names: self.dict.pop(key, None) + self.committed_state.pop(key, None) if not getattr(self.class_, key).impl.accepts_global_callable: continue diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index ddeaaf8ad..55001dc70 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -1398,9 +1398,8 @@ class ColumnElement(ClauseElement, _CompareMixin): docstring for more details. """ - def __init__(self): - self.primary_key = False - self.foreign_keys = [] + primary_key = False + foreign_keys = [] def base_columns(self): if hasattr(self, '_base_columns'): @@ -1557,7 +1556,6 @@ class FromClause(Selectable): self.oid_column = None def _get_from_objects(self, **modifiers): - # this could also be [self], at the moment it doesnt matter to the Select object return [] def default_order_by(self): @@ -2486,7 +2484,6 @@ class _ColumnElementAdapter(ColumnElement): """ def __init__(self, elem): - ColumnElement.__init__(self) self.elem = elem self.type = getattr(elem, 'type', None) @@ -2900,8 +2897,11 @@ class _ScalarSelect(_Grouping): __visit_name__ = 'grouping' def __init__(self, elem): - super(_ScalarSelect, self).__init__(elem) - self.type = list(elem.inner_columns)[0].type + self.elem = elem + cols = list(elem.inner_columns) + if len(cols) != 1: + raise exceptions.InvalidRequestError("Scalar select can only be created from a Select object that has exactly one column expression.") + self.type = cols[0].type def _no_cols(self): raise exceptions.InvalidRequestError("Scalar Select expression has no columns; use this object directly within a column-level expression.") @@ -3086,6 +3086,10 @@ class Select(_SelectBaseMixin, FromClause): froms = property(_get_display_froms, doc="""Return a list of all FromClause elements which will be applied to the FROM clause of the resulting statement.""") + def type(self): + raise exceptions.InvalidRequestError("Select objects don't have a type. Call as_scalar() on this Select object to return a 'scalar' version of this Select.") + type = property(type) + def locate_all_froms(self): """return a Set of all FromClause elements referenced by this Select. |
