summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/schema.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-03-24 10:55:29 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-03-24 10:55:29 -0400
commitbdcaa0f6ca580b54b9c25178441fcbe8f2a4e387 (patch)
tree61a80475ad22f83067ab0b2fe1df65b709f3a2c1 /lib/sqlalchemy/sql/schema.py
parent04545727d4117db51786189e591b1777bde1a40b (diff)
downloadsqlalchemy-bdcaa0f6ca580b54b9c25178441fcbe8f2a4e387.tar.gz
- The "auto-attach" feature of constraints such as :class:`.UniqueConstraint`
and :class:`.CheckConstraint` has been further enhanced such that when the constraint is associated with non-table-bound :class:`.Column` objects, the constraint will set up event listeners with the columns themselves such that the constraint auto attaches at the same time the columns are associated with the table. This in particular helps in some edge cases in declarative but is also of general use. fixes #3341
Diffstat (limited to 'lib/sqlalchemy/sql/schema.py')
-rw-r--r--lib/sqlalchemy/sql/schema.py54
1 files changed, 37 insertions, 17 deletions
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index e022c5768..3aeba9804 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -2390,24 +2390,44 @@ class ColumnCollectionMixin(object):
self._pending_colargs = [_to_schema_column_or_string(c)
for c in columns]
if _autoattach and self._pending_colargs:
- columns = [
- c for c in self._pending_colargs
- if isinstance(c, Column) and
- isinstance(c.table, Table)
- ]
+ self._check_attach()
- tables = set([c.table for c in columns])
- if len(tables) == 1:
- self._set_parent_with_dispatch(tables.pop())
- elif len(tables) > 1 and not self._allow_multiple_tables:
- table = columns[0].table
- others = [c for c in columns[1:] if c.table is not table]
- if others:
- raise exc.ArgumentError(
- "Column(s) %s are not part of table '%s'." %
- (", ".join("'%s'" % c for c in others),
- table.description)
- )
+ def _check_attach(self, evt=False):
+ col_objs = [
+ c for c in self._pending_colargs
+ if isinstance(c, Column)
+ ]
+ cols_w_table = [
+ c for c in col_objs if isinstance(c.table, Table)
+ ]
+ cols_wo_table = set(col_objs).difference(cols_w_table)
+
+ if cols_wo_table:
+ assert not evt, "Should not reach here on event call"
+
+ def _col_attached(column, table):
+ cols_wo_table.discard(column)
+ if not cols_wo_table:
+ self._check_attach(evt=True)
+ self._cols_wo_table = cols_wo_table
+ for col in cols_wo_table:
+ col._on_table_attach(_col_attached)
+ return
+
+ columns = cols_w_table
+
+ tables = set([c.table for c in columns])
+ if len(tables) == 1:
+ self._set_parent_with_dispatch(tables.pop())
+ elif len(tables) > 1 and not self._allow_multiple_tables:
+ table = columns[0].table
+ others = [c for c in columns[1:] if c.table is not table]
+ if others:
+ raise exc.ArgumentError(
+ "Column(s) %s are not part of table '%s'." %
+ (", ".join("'%s'" % c for c in others),
+ table.description)
+ )
def _set_parent(self, table):
for col in self._pending_colargs: