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::
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 \
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
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()."""