]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- clean it up a bit
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 20 Dec 2010 21:21:31 +0000 (16:21 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 20 Dec 2010 21:21:31 +0000 (16:21 -0500)
- don't need __set_composite_values__()
- break the bad news about mutations

doc/build/orm/extensions/hybrid.rst
doc/build/orm/mapper_config.rst
lib/sqlalchemy/orm/descriptor_props.py

index e986f170212cb83276f516fea9af536d1f2f5e1c..251c872ddfcbf73ae98fe05634e4e05de392f87c 100644 (file)
@@ -1,3 +1,5 @@
+.. _hybrids_toplevel:
+
 Hybrid Attributes
 =================
 
index 40512f520e6a6fe4d8b52d6feff03a200b15fbad..6e0023ae410cd78ec70c67f84e209d7ef63b1515 100644 (file)
@@ -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
index f9df47030daaec6487be0c41fc9ea006ae3afe23..18c1081f377a9ccfdb38b3d33fb98a8c974b83eb 100644 (file)
@@ -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()."""