summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-01-01 13:24:32 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-01-01 13:39:42 -0500
commit8f5e4acbf693a375ad687977188a32bc941fd33b (patch)
tree8965514460dbfa69fa99972c0443751ae70f178a
parentda1aa2590851bd5ddc58218fab0e8234d16db97c (diff)
downloadsqlalchemy-8f5e4acbf693a375ad687977188a32bc941fd33b.tar.gz
- Added a new accessor :attr:`.Table.foreign_key_constraints`
to complement the :attr:`.Table.foreign_keys` collection, as well as :attr:`.ForeignKeyConstraint.referred_table`.
-rw-r--r--doc/build/changelog/changelog_10.rst7
-rw-r--r--lib/sqlalchemy/sql/schema.py27
-rw-r--r--test/sql/test_metadata.py40
3 files changed, 74 insertions, 0 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index 3564ecde1..4b3a17367 100644
--- a/doc/build/changelog/changelog_10.rst
+++ b/doc/build/changelog/changelog_10.rst
@@ -23,6 +23,13 @@
on compatibility concerns, see :doc:`/changelog/migration_10`.
.. change::
+ :tags: feature, schema
+
+ Added a new accessor :attr:`.Table.foreign_key_constraints`
+ to complement the :attr:`.Table.foreign_keys` collection,
+ as well as :attr:`.ForeignKeyConstraint.referred_table`.
+
+ .. change::
:tags: bug, sqlite
:tickets: 3244, 3261
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index b134b3053..71a0c2780 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -516,6 +516,19 @@ class Table(DialectKWArgs, SchemaItem, TableClause):
"""
return sorted(self.constraints, key=lambda c: c._creation_order)
+ @property
+ def foreign_key_constraints(self):
+ """:class:`.ForeignKeyConstraint` objects referred to by this
+ :class:`.Table`.
+
+ This list is produced from the collection of :class:`.ForeignKey`
+ objects currently associated.
+
+ .. versionadded:: 1.0.0
+
+ """
+ return set(fkc.constraint for fkc in self.foreign_keys)
+
def _init_existing(self, *args, **kwargs):
autoload_with = kwargs.pop('autoload_with', None)
autoload = kwargs.pop('autoload', autoload_with is not None)
@@ -2632,6 +2645,20 @@ class ForeignKeyConstraint(ColumnCollectionConstraint):
else:
return None
+ @property
+ def referred_table(self):
+ """The :class:`.Table` object to which this
+ :class:`.ForeignKeyConstraint references.
+
+ This is a dynamically calculated attribute which may not be available
+ if the constraint and/or parent table is not yet associated with
+ a metadata collection that contains the referred table.
+
+ .. versionadded:: 1.0.0
+
+ """
+ return self.elements[0].column.table
+
def _validate_dest_table(self, table):
table_keys = set([elem._table_key()
for elem in self.elements])
diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py
index 52ecf88c5..cc7d0eb4f 100644
--- a/test/sql/test_metadata.py
+++ b/test/sql/test_metadata.py
@@ -1196,6 +1196,30 @@ class TableTest(fixtures.TestBase, AssertsCompiledSQL):
t.info['bar'] = 'zip'
assert t.info['bar'] == 'zip'
+ def test_foreign_key_constraints_collection(self):
+ metadata = MetaData()
+ t1 = Table('foo', metadata, Column('a', Integer))
+ eq_(t1.foreign_key_constraints, set())
+
+ fk1 = ForeignKey('q.id')
+ fk2 = ForeignKey('j.id')
+ fk3 = ForeignKeyConstraint(['b', 'c'], ['r.x', 'r.y'])
+
+ t1.append_column(Column('b', Integer, fk1))
+ eq_(
+ t1.foreign_key_constraints,
+ set([fk1.constraint]))
+
+ t1.append_column(Column('c', Integer, fk2))
+ eq_(
+ t1.foreign_key_constraints,
+ set([fk1.constraint, fk2.constraint]))
+
+ t1.append_constraint(fk3)
+ eq_(
+ t1.foreign_key_constraints,
+ set([fk1.constraint, fk2.constraint, fk3]))
+
def test_c_immutable(self):
m = MetaData()
t1 = Table('t', m, Column('x', Integer), Column('y', Integer))
@@ -1947,6 +1971,22 @@ class ConstraintTest(fixtures.TestBase):
assert s1.c.a.references(t1.c.a)
assert not s1.c.a.references(t1.c.b)
+ def test_referred_table_accessor(self):
+ t1, t2, t3 = self._single_fixture()
+ fkc = list(t2.foreign_key_constraints)[0]
+ is_(fkc.referred_table, t1)
+
+ def test_referred_table_accessor_not_available(self):
+ t1 = Table('t', MetaData(), Column('x', ForeignKey('q.id')))
+ fkc = list(t1.foreign_key_constraints)[0]
+ assert_raises_message(
+ exc.InvalidRequestError,
+ "Foreign key associated with column 't.x' could not find "
+ "table 'q' with which to generate a foreign key to target "
+ "column 'id'",
+ getattr, fkc, "referred_table"
+ )
+
def test_related_column_not_present_atfirst_ok(self):
m = MetaData()
base_table = Table("base", m,