diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-11-05 14:52:35 -0500 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2018-11-10 16:13:01 -0500 |
commit | be705595846cd2205c72f9d87c025f8dc530cb73 (patch) | |
tree | d690bf7efe8c7d9e8b52472aa9b8db6a1b8e75e7 /lib/sqlalchemy/sql/naming.py | |
parent | 15ac07f7b6c235131361f289d75d174c49afb0b5 (diff) | |
download | sqlalchemy-be705595846cd2205c72f9d87c025f8dc530cb73.tar.gz |
Add new "all columns" naming convention tokens
Added new naming convention tokens ``column_0N_name``, ``column_0_N_name``,
etc., which will render the names / keys / labels for all columns referenced
by a particular constraint in a sequence. In order to accommodate for the
length of such a naming convention, the SQL compiler's auto-truncation
feature now applies itself to constraint names as well, which creates a
shortened, deterministically generated name for the constraint that will
apply to a target backend without going over the character limit of that
backend.
Additional notes:
1. the SQLite dialect had a format_index method that was apparently not
used, removed.
2. the naming convention logic has been applying the foreign key
remote column spec to the naming convention, and not the actual
column name. In the case where the referenced Table object uses
.key inside the columns and these are what ForeignKey() references,
the naming convention was doing the wrong thing. The patch here
fixes this, however this isn't noted in the migration notes.
Fixes: #3989
Change-Id: Ib24f4754b886676096c480fc54b2e5c2463ac99a
Diffstat (limited to 'lib/sqlalchemy/sql/naming.py')
-rw-r--r-- | lib/sqlalchemy/sql/naming.py | 43 |
1 files changed, 32 insertions, 11 deletions
diff --git a/lib/sqlalchemy/sql/naming.py b/lib/sqlalchemy/sql/naming.py index 533429333..0107ce724 100644 --- a/lib/sqlalchemy/sql/naming.py +++ b/lib/sqlalchemy/sql/naming.py @@ -48,6 +48,12 @@ class ConventionDict(object): self.const.name = None return self._const_name + def _key_column_X_key(self, idx): + # 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 + def _key_column_X_name(self, idx): return self._column_X(idx).name @@ -65,12 +71,10 @@ class ConventionDict(object): def _key_referred_column_X_name(self, idx): fk = self.const.elements[idx] - refs = fk.target_fullname.split(".") - if len(refs) == 3: - refschema, reftable, refcol = refs - else: - reftable, refcol = refs - return refcol + # note that before [ticket:3989], this method was returning + # the specification for the :class:`.ForeignKey` itself, which normally + # would be using the ``.key`` of the column, not the name. + return fk.column.name def __getitem__(self, key): if key in self.convention: @@ -78,13 +82,30 @@ class ConventionDict(object): elif hasattr(self, '_key_%s' % key): return getattr(self, '_key_%s' % key)() else: - col_template = re.match(r".*_?column_(\d+)_.+", key) + col_template = re.match(r".*_?column_(\d+)(_?N)?_.+", key) if col_template: idx = col_template.group(1) - attr = "_key_" + key.replace(idx, "X") - idx = int(idx) - if hasattr(self, attr): - return getattr(self, attr)(idx) + multiples = col_template.group(2) + + if multiples: + if self._is_fk: + elems = self.const.elements + else: + elems = list(self.const.columns) + tokens = [] + for idx, elem in enumerate(elems): + attr = "_key_" + key.replace("0" + multiples, "X") + try: + tokens.append(getattr(self, attr)(idx)) + except AttributeError: + raise KeyError(key) + sep = "_" if multiples.startswith("_") else "" + return sep.join(tokens) + else: + attr = "_key_" + key.replace(idx, "X") + idx = int(idx) + if hasattr(self, attr): + return getattr(self, attr)(idx) raise KeyError(key) _prefix_dict = { |