]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Column calls _set_parent() on child items within the constructor, so that the Column...
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 28 Jun 2009 20:31:01 +0000 (20:31 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sun, 28 Jun 2009 20:31:01 +0000 (20:31 +0000)
navigable before table attachment.  helps migrate.

lib/sqlalchemy/schema.py
test/orm/test_eager_relations.py
test/sql/test_constraints.py

index 8f6516c631f2dceb9468f98b2ad443711d90ca04..d85f36b39ed152ef8174c5b838fba7fe0bb32844 100644 (file)
@@ -407,7 +407,7 @@ class Column(SchemaItem, expression.ColumnClause):
     """Represents a column in a database table."""
 
     __visit_name__ = 'column'
-
+    
     def __init__(self, *args, **kwargs):
         """
         Construct a new ``Column`` object.
@@ -577,7 +577,6 @@ class Column(SchemaItem, expression.ColumnClause):
                 type_ = args.pop(0)
 
         super(Column, self).__init__(name, None, type_)
-        self._pending_args = args
         self.key = kwargs.pop('key', name)
         self.primary_key = kwargs.pop('primary_key', False)
         self.nullable = kwargs.pop('nullable', not self.primary_key)
@@ -591,6 +590,28 @@ class Column(SchemaItem, expression.ColumnClause):
         self.autoincrement = kwargs.pop('autoincrement', True)
         self.constraints = set()
         self.foreign_keys = util.OrderedSet()
+        self._table_events = set()
+        
+        if self.default is not None:
+            if isinstance(self.default, ColumnDefault):
+                args.append(self.default)
+            else:
+                args.append(ColumnDefault(self.default))
+        if self.server_default is not None:
+            if isinstance(self.server_default, FetchedValue):
+                args.append(self.server_default)
+            else:
+                args.append(DefaultClause(self.server_default))
+        if self.onupdate is not None:
+            args.append(ColumnDefault(self.onupdate, for_update=True))
+        if self.server_onupdate is not None:
+            if isinstance(self.server_onupdate, FetchedValue):
+                args.append(self.server_default)
+            else:
+                args.append(DefaultClause(self.server_onupdate,
+                                            for_update=True))
+        self._init_items(*args)
+
         util.set_creation_order(self)
 
         if kwargs.get('info'):
@@ -688,28 +709,16 @@ class Column(SchemaItem, expression.ColumnClause):
                     "external to the Table.")
             table.append_constraint(UniqueConstraint(self.key))
 
-        toinit = list(self._pending_args)
-        if self.default is not None:
-            if isinstance(self.default, ColumnDefault):
-                toinit.append(self.default)
-            else:
-                toinit.append(ColumnDefault(self.default))
-        if self.server_default is not None:
-            if isinstance(self.server_default, FetchedValue):
-                toinit.append(self.server_default)
-            else:
-                toinit.append(DefaultClause(self.server_default))
-        if self.onupdate is not None:
-            toinit.append(ColumnDefault(self.onupdate, for_update=True))
-        if self.server_onupdate is not None:
-            if isinstance(self.server_onupdate, FetchedValue):
-                toinit.append(self.server_default)
-            else:
-                toinit.append(DefaultClause(self.server_onupdate,
-                                            for_update=True))
-        self._init_items(*toinit)
-        del self._pending_args
-
+        for fn in self._table_events:
+            fn(table)
+        del self._table_events
+    
+    def _on_table_attach(self, fn):
+        if self.table:
+            fn(self.table)
+        else:
+            self._table_events.add(fn)
+            
     def copy(self, **kw):
         """Create a copy of this ``Column``, unitialized.
 
@@ -732,14 +741,15 @@ class Column(SchemaItem, expression.ColumnClause):
         """Create a *proxy* for this column.
 
         This is a copy of this ``Column`` referenced by a different parent
-        (such as an alias or select statement).
-
+        (such as an alias or select statement).  The column should
+        be used only in select scenarios, as its full DDL/default
+        information is not transferred.
+        
         """
         fk = [ForeignKey(f.column) for f in self.foreign_keys]
         c = Column(
             name or self.name, 
             self.type, 
-            self.default, 
             key = name or self.key, 
             primary_key = self.primary_key, 
             nullable = self.nullable, 
@@ -749,8 +759,9 @@ class Column(SchemaItem, expression.ColumnClause):
         selectable.columns.add(c)
         if self.primary_key:
             selectable.primary_key.add(c)
-        for f in fk:
-            c._init_items(f)
+        for fn in c._table_events:
+            fn(selectable)
+        del c._table_events
         return c
 
     def get_children(self, schema_visitor=False, **kwargs):
@@ -959,18 +970,20 @@ class ForeignKey(SchemaItem):
             raise exc.InvalidRequestError("This ForeignKey already has a parent !")
         self.parent = column
 
-        if self.constraint is None and isinstance(self.parent.table, Table):
+        self.parent.foreign_keys.add(self)
+        self.parent._on_table_attach(self._set_table)
+    
+    def _set_table(self, table):
+        if self.constraint is None and isinstance(table, Table):
             self.constraint = ForeignKeyConstraint(
                 [], [], use_alter=self.use_alter, name=self.name,
                 onupdate=self.onupdate, ondelete=self.ondelete,
                 deferrable=self.deferrable, initially=self.initially,
                 )
-            self.constraint._elements[column] = self
-            self.constraint._set_parent(self.parent.table)
-
-        self.parent.foreign_keys.add(self)
-        self.parent.table.foreign_keys.add(self)
-
+            self.constraint._elements[self.parent] = self
+            self.constraint._set_parent(table)
+        table.foreign_keys.add(self)
+        
 class DefaultGenerator(SchemaItem):
     """Base class for column *default* values."""
 
@@ -1086,7 +1099,11 @@ class Sequence(DefaultGenerator):
     def _set_parent(self, column):
         super(Sequence, self)._set_parent(column)
         column.sequence = self
-        self.metadata = column.table.metadata
+        
+        column._on_table_attach(self._set_table)
+    
+    def _set_table(self, table):
+        self.metadata = table.metadata
         
     @property
     def bind(self):
index e853a85c1f59fc0d735dd74475f229d938fa3f25..3eabe2db72474d58800366f9d05c300adcea1621 100644 (file)
@@ -659,6 +659,7 @@ class EagerTest(_fixtures.FixtureTest):
                'orders':relation(Order, backref='user', lazy=False),
                'max_order':relation(mapper(Order, max_orders, non_primary=True), lazy=False, uselist=False)
                })
+
         q = create_session().query(User)
 
         def go():
index 2dbf181176d6f354d110264c9bafbd3ef9d202a6..6188357c3596a532989d45344d4def4f77402aa1 100644 (file)
@@ -37,10 +37,8 @@ class ConstraintTest(TestBase, AssertsExecutionResults, AssertsCompiledSQL):
     def test_double_fk_usage_raises(self):
         f = ForeignKey('b.id')
         
-        assert_raises(exc.InvalidRequestError, Table, "a", metadata,
-            Column('x', Integer, f),
-            Column('y', Integer, f)
-        )
+        Column('x', Integer, f)
+        assert_raises(exc.InvalidRequestError, Column, "y", Integer, f)
         
     def test_circular_constraint(self):
         a = Table("a", metadata,