summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql/naming.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2021-02-04 12:09:54 -0500
committerMike Bayer <mike_mp@zzzcomputing.com>2021-02-04 12:11:41 -0500
commit9660e94e35be438b0d51cd87e6ccb4047a332c15 (patch)
tree0a888b4fb18430618bca045b3c2456dff893f6cb /lib/sqlalchemy/sql/naming.py
parente91d918fc24d678a413feb3744e70014f54172c7 (diff)
downloadsqlalchemy-9660e94e35be438b0d51cd87e6ccb4047a332c15.tar.gz
Accommodate column-based naming conventions for pk constraint
Repaired / implemented support for primary key constraint naming conventions that use column names/keys/etc as part of the convention. In particular, this includes that the :class:`.PrimaryKeyConstraint` object that's automatically associated with a :class:`.schema.Table` will update its name as new primary key :class:`_schema.Column` objects are added to the table and then to the constraint. Internal failure modes related to this constraint construction process including no columns present, no name present or blank name present are now accommodated. Fixes: #5919 Change-Id: Ic2800b50f4a4cd5978bec48cefea0a2e198e0123
Diffstat (limited to 'lib/sqlalchemy/sql/naming.py')
-rw-r--r--lib/sqlalchemy/sql/naming.py45
1 files changed, 37 insertions, 8 deletions
diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py
index 130ec6875..005c41683 100644
--- a/lib/sqlalchemy/sql/naming.py
+++ b/lib/sqlalchemy/sql/naming.py
@@ -39,12 +39,22 @@ class ConventionDict(object):
def _key_table_name(self):
return self.table.name
- def _column_X(self, idx):
+ def _column_X(self, idx, attrname):
if self._is_fk:
- fk = self.const.elements[idx]
- return fk.parent
+ try:
+ fk = self.const.elements[idx]
+ except IndexError:
+ return ""
+ else:
+ return getattr(fk.parent, attrname)
else:
- return list(self.const.columns)[idx]
+ cols = list(self.const.columns)
+ try:
+ col = cols[idx]
+ except IndexError:
+ return ""
+ else:
+ return getattr(col, attrname)
def _key_constraint_name(self):
if isinstance(self._const_name, (type(None), _defer_none_name)):
@@ -61,13 +71,13 @@ class ConventionDict(object):
# note this method was missing before
# [ticket:3989], meaning tokens like ``%(column_0_key)s`` weren't
# working even though documented.
- return self._column_X(idx).key
+ return self._column_X(idx, "key")
def _key_column_X_name(self, idx):
- return self._column_X(idx).name
+ return self._column_X(idx, "name")
def _key_column_X_label(self, idx):
- return self._column_X(idx)._ddl_label
+ return self._column_X(idx, "_ddl_label")
def _key_referred_table_name(self):
fk = self.const.elements[0]
@@ -161,10 +171,28 @@ def _constraint_name_for_table(const, table):
return None
+@event.listens_for(
+ PrimaryKeyConstraint, "_sa_event_column_added_to_pk_constraint"
+)
+def _column_added_to_pk_constraint(pk_constraint, col):
+ if pk_constraint._implicit_generated:
+ # only operate upon the "implicit" pk constraint for now,
+ # as we have to force the name to None to reset it. the
+ # "implicit" constraint will only have a naming convention name
+ # if at all.
+ table = pk_constraint.table
+ pk_constraint.name = None
+ newname = _constraint_name_for_table(pk_constraint, table)
+ if newname:
+ pk_constraint.name = newname
+
+
@event.listens_for(Constraint, "after_parent_attach")
@event.listens_for(Index, "after_parent_attach")
def _constraint_name(const, table):
if isinstance(table, Column):
+ # this path occurs for a CheckConstraint linked to a Column
+
# for column-attached constraint, set another event
# to link the column attached to the table as this constraint
# associated with the table.
@@ -173,10 +201,11 @@ def _constraint_name(const, table):
"after_parent_attach",
lambda col, table: _constraint_name(const, table),
)
+
elif isinstance(table, Table):
if isinstance(const.name, (conv, _defer_name)):
return
newname = _constraint_name_for_table(const, table)
- if newname is not None:
+ if newname:
const.name = newname