summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/schema.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r--lib/sqlalchemy/schema.py54
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)