diff options
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r-- | lib/sqlalchemy/schema.py | 54 |
1 files changed, 46 insertions, 8 deletions
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index ef9137ecd..8761b7be6 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -794,9 +794,11 @@ class Column(SchemaItem, expression.ColumnClause): This is used in ``Table.tometadata``. """ - args = [c.copy(**kw) for c in self.constraints] - if self.table is None: - args += [c.copy(**kw) for c in self.foreign_keys] + + # Constraint objects plus non-constraint-bound ForeignKey objects + args = \ + [c.copy(**kw) for c in self.constraints] + \ + [c.copy(**kw) for c in self.foreign_keys if not c.constraint] return Column( name=self.name, @@ -849,7 +851,7 @@ class Column(SchemaItem, expression.ColumnClause): class ForeignKey(SchemaItem): - """Defines a column-level FOREIGN KEY constraint between two columns. + """Defines a dependency between two columns. ``ForeignKey`` is specified as an argument to a :class:`Column` object, e.g.:: @@ -857,10 +859,28 @@ class ForeignKey(SchemaItem): t = Table("remote_table", metadata, Column("remote_id", ForeignKey("main_table.id")) ) - - For a composite (multiple column) FOREIGN KEY, use a - :class:`ForeignKeyConstraint` object specified at the level of the - :class:`Table`. + + Note that ``ForeignKey`` is only a marker object that defines + a dependency between two columns. The actual constraint + is in all cases represented by the :class:`ForeignKeyConstraint` + object. This object will be generated automatically when + a ``ForeignKey`` is associated with a :class:`Column` which + in turn is associated with a :class:`Table`. Conversely, + when :class:`ForeignKeyConstraint` is applied to a :class:`Table`, + ``ForeignKey`` markers are automatically generated to be + present on each associated :class:`Column`, which are also + associated with the constraint object. + + Note that you cannot define a "composite" foreign key constraint, + that is a constraint between a grouping of multiple parent/child + columns, using ``ForeignKey`` objects. To define this grouping, + the :class:`ForeignKeyConstraint` object must be used, and applied + to the :class:`Table`. The associated ``ForeignKey`` objects + are created automatically. + + The ``ForeignKey`` objects associated with an individual + :class:`Column` object are available in the `foreign_keys` collection + of that column. Further examples of foreign key configuration are in :ref:`metadata_foreignkeys`. @@ -915,7 +935,15 @@ class ForeignKey(SchemaItem): """ self._colspec = column + + # the linked ForeignKeyConstraint. + # ForeignKey will create this when parent Column + # is attached to a Table, *or* ForeignKeyConstraint + # object passes itself in when creating ForeignKey + # markers. self.constraint = _constraint + + self.use_alter = use_alter self.name = name self.onupdate = onupdate @@ -929,6 +957,7 @@ class ForeignKey(SchemaItem): def copy(self, schema=None): """Produce a copy of this ForeignKey object.""" + return ForeignKey( self._get_colspec(schema=schema), use_alter=self.use_alter, @@ -1061,6 +1090,8 @@ class ForeignKey(SchemaItem): self.parent._on_table_attach(self._set_table) def _set_table(self, table, column): + # standalone ForeignKey - create ForeignKeyConstraint + # on the hosting Table when attached to the Table. if self.constraint is None and isinstance(table, Table): self.constraint = ForeignKeyConstraint( [], [], use_alter=self.use_alter, name=self.name, @@ -1491,6 +1522,11 @@ class ForeignKeyConstraint(Constraint): self.use_alter = use_alter self._elements = util.OrderedDict() + + # standalone ForeignKeyConstraint - create + # associated ForeignKey objects which will be applied to hosted + # Column objects (in col.foreign_keys), either now or when attached + # to the Table for string-specified names for col, refcol in zip(columns, refcolumns): self._elements[col] = ForeignKey( refcol, @@ -1516,6 +1552,8 @@ class ForeignKeyConstraint(Constraint): def _set_parent(self, table): super(ForeignKeyConstraint, self)._set_parent(table) for col, fk in self._elements.iteritems(): + # string-specified column names now get + # resolved to Column objects if isinstance(col, basestring): col = table.c[col] fk._set_parent(col) |