summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/schema.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-01-30 13:38:51 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2015-01-30 13:38:51 -0500
commit383bb3f708168aedb1832050a84ff054f8211386 (patch)
tree3bc8837150ab66a2be63c780ac5912f5cb89e5bc /lib/sqlalchemy/sql/schema.py
parent3712e35c329cc3b5106f026be90e04f65412586d (diff)
downloadsqlalchemy-383bb3f708168aedb1832050a84ff054f8211386.tar.gz
- The :class:`.CheckConstraint` construct now supports naming
conventions that include the token ``%(column_0_name)s``; the constraint expression is scanned for columns. Additionally, naming conventions for check constraints that don't include the ``%(constraint_name)s`` token will now work for :class:`.SchemaType`- generated constraints, such as those of :class:`.Boolean` and :class:`.Enum`; this stopped working in 0.9.7 due to :ticket:`3067`. fixes #3299
Diffstat (limited to 'lib/sqlalchemy/sql/schema.py')
-rw-r--r--lib/sqlalchemy/sql/schema.py61
1 files changed, 37 insertions, 24 deletions
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index f3752a726..fa48a16cc 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -2381,14 +2381,32 @@ class ColumnCollectionMixin(object):
"""
- def __init__(self, *columns):
+ _allow_multiple_tables = False
+
+ def __init__(self, *columns, **kw):
+ _autoattach = kw.pop('_autoattach', True)
self.columns = ColumnCollection()
self._pending_colargs = [_to_schema_column_or_string(c)
for c in columns]
- if self._pending_colargs and \
- isinstance(self._pending_colargs[0], Column) and \
- isinstance(self._pending_colargs[0].table, Table):
- self._set_parent_with_dispatch(self._pending_colargs[0].table)
+ if _autoattach and self._pending_colargs:
+ columns = [
+ c for c in self._pending_colargs
+ if isinstance(c, Column) and
+ isinstance(c.table, 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:
@@ -2420,8 +2438,9 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
arguments are propagated to the :class:`.Constraint` superclass.
"""
+ _autoattach = kw.pop('_autoattach', True)
Constraint.__init__(self, **kw)
- ColumnCollectionMixin.__init__(self, *columns)
+ ColumnCollectionMixin.__init__(self, *columns, _autoattach=_autoattach)
def _set_parent(self, table):
Constraint._set_parent(self, table)
@@ -2449,12 +2468,14 @@ class ColumnCollectionConstraint(ColumnCollectionMixin, Constraint):
return len(self.columns._data)
-class CheckConstraint(Constraint):
+class CheckConstraint(ColumnCollectionConstraint):
"""A table- or column-level CHECK constraint.
Can be included in the definition of a Table or Column.
"""
+ _allow_multiple_tables = True
+
def __init__(self, sqltext, name=None, deferrable=None,
initially=None, table=None, info=None, _create_rule=None,
_autoattach=True, _type_bound=False):
@@ -2486,20 +2507,19 @@ class CheckConstraint(Constraint):
"""
+ self.sqltext = _literal_as_text(sqltext, warn=False)
+
+ columns = []
+ visitors.traverse(self.sqltext, {}, {'column': columns.append})
+
super(CheckConstraint, self).\
__init__(
- name, deferrable, initially, _create_rule, info=info,
- _type_bound=_type_bound)
- self.sqltext = _literal_as_text(sqltext, warn=False)
+ name=name, deferrable=deferrable,
+ initially=initially, _create_rule=_create_rule, info=info,
+ _type_bound=_type_bound, _autoattach=_autoattach,
+ *columns)
if table is not None:
self._set_parent_with_dispatch(table)
- elif _autoattach:
- cols = _find_columns(self.sqltext)
- tables = set([c.table for c in cols
- if isinstance(c.table, Table)])
- if len(tables) == 1:
- self._set_parent_with_dispatch(
- tables.pop())
def __visit_name__(self):
if isinstance(self.parent, Table):
@@ -2741,7 +2761,6 @@ class ForeignKeyConstraint(ColumnCollectionConstraint):
self._validate_dest_table(table)
-
def copy(self, schema=None, target_table=None, **kw):
fkc = ForeignKeyConstraint(
[x.parent.key for x in self.elements],
@@ -3064,12 +3083,6 @@ class Index(DialectKWArgs, ColumnCollectionMixin, SchemaItem):
)
)
self.table = table
- for c in self.columns:
- if c.table != self.table:
- raise exc.ArgumentError(
- "Column '%s' is not part of table '%s'." %
- (c, self.table.description)
- )
table.indexes.add(self)
self.expressions = [