From: Mike Bayer Date: Mon, 20 Dec 2010 21:21:31 +0000 (-0500) Subject: - clean it up a bit X-Git-Tag: rel_0_7b1~136 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=11f2bdff3171470a899ef684d2b833415ce791e5;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - clean it up a bit - don't need __set_composite_values__() - break the bad news about mutations --- diff --git a/doc/build/orm/extensions/hybrid.rst b/doc/build/orm/extensions/hybrid.rst index e986f17021..251c872ddf 100644 --- a/doc/build/orm/extensions/hybrid.rst +++ b/doc/build/orm/extensions/hybrid.rst @@ -1,3 +1,5 @@ +.. _hybrids_toplevel: + Hybrid Attributes ================= diff --git a/doc/build/orm/mapper_config.rst b/doc/build/orm/mapper_config.rst index 40512f520e..6e0023ae41 100644 --- a/doc/build/orm/mapper_config.rst +++ b/doc/build/orm/mapper_config.rst @@ -488,8 +488,15 @@ or aliasing that has been applied in the context of the generated SQL statement. Composite Column Types ----------------------- -Sets of columns can be associated with a single user-defined datatype. The ORM provides a single attribute which represents the group of columns -using the class you provide. +Sets of columns can be associated with a single user-defined datatype. The ORM +provides a single attribute which represents the group of columns using the +class you provide. + +.. note:: + As of SQLAlchemy 0.7, composites are implemented as a simple wrapper using + the :ref:`hybrids_toplevel` feature. Note that composites no longer + "conceal" the underlying colunm based attributes, or support in-place + mutation. A simple example represents pairs of columns as a "Point" object. Starting with a table that represents two points as x1/y1 and x2/y2:: @@ -513,9 +520,6 @@ pair:: self.y = y def __composite_values__(self): return self.x, self.y - def __set_composite_values__(self, x, y): - self.x = x - self.y = y def __eq__(self, other): return other is not None and \ other.x == self.x and \ @@ -530,10 +534,6 @@ returns the state of the object as a list or tuple, in order of its column-based attributes. It also should supply adequate ``__eq__()`` and ``__ne__()`` methods which test the equality of two instances. -The ``__set_composite_values__()`` method is optional. If it's not -provided, the names of the mapped columns are taken as the names of -attributes on the object, and ``setattr()`` is used to set data. - The :func:`.composite` function is then used in the mapping:: from sqlalchemy.orm import composite diff --git a/lib/sqlalchemy/orm/descriptor_props.py b/lib/sqlalchemy/orm/descriptor_props.py index f9df47030d..18c1081f37 100644 --- a/lib/sqlalchemy/orm/descriptor_props.py +++ b/lib/sqlalchemy/orm/descriptor_props.py @@ -104,23 +104,33 @@ class CompositeProperty(DescriptorProperty): self.deferred = kwargs.get('deferred', False) self.group = kwargs.get('group', None) - prop = self def fget(instance): - return prop.composite_class( - *[getattr(instance, prop.parent._columntoproperty[col].key) - for col in prop.columns] + # this could be optimized to store the value in __dict__, + # but more complexity and tests would be needed to pick + # up on changes to the mapped columns made independently + # of those on the composite. + return self.composite_class( + *[getattr(instance, key) for key in self._attribute_keys] ) + def fset(instance, value): if value is None: fdel(instance) else: - for col, value in zip(prop.columns, value.__composite_values__()): - setattr(instance, prop.parent._columntoproperty[col].key, value) + for key, value in zip(self._attribute_keys, value.__composite_values__()): + setattr(instance, key, value) def fdel(instance): - for col in prop.columns: - setattr(instance, prop.parent._columntoproperty[col].key, None) + for key in self._attribute_keys: + setattr(instance, key, None) self.descriptor = property(fget, fset, fdel) + + @util.memoized_property + def _attribute_keys(self): + return [ + self.parent._columntoproperty[col].key + for col in self.columns + ] def get_history(self, state, dict_, **kw): """Provided for userland code that uses attributes.get_history()."""