summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/sql
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/sql')
-rw-r--r--lib/sqlalchemy/sql/schema.py41
-rw-r--r--lib/sqlalchemy/sql/util.py2
2 files changed, 39 insertions, 4 deletions
diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py
index 447e102ed..c37b60003 100644
--- a/lib/sqlalchemy/sql/schema.py
+++ b/lib/sqlalchemy/sql/schema.py
@@ -2271,10 +2271,19 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
information is not transferred.
"""
+
fk = [
- ForeignKey(f.column, _constraint=f.constraint)
- for f in self.foreign_keys
+ ForeignKey(
+ col if col is not None else f._colspec,
+ _unresolvable=col is None,
+ _constraint=f.constraint,
+ )
+ for f, col in [
+ (fk, fk._resolve_column(raiseerr=False))
+ for fk in self.foreign_keys
+ ]
]
+
if name is None and self.name is None:
raise exc.InvalidRequestError(
"Cannot initialize a sub-selectable"
@@ -2375,6 +2384,7 @@ class ForeignKey(DialectKWArgs, SchemaItem):
link_to_name: bool = False,
match: Optional[str] = None,
info: Optional[_InfoType] = None,
+ _unresolvable: bool = False,
**dialect_kw: Any,
):
r"""
@@ -2448,6 +2458,7 @@ class ForeignKey(DialectKWArgs, SchemaItem):
"""
self._colspec = coercions.expect(roles.DDLReferredColumnRole, column)
+ self._unresolvable = _unresolvable
if isinstance(self._colspec, str):
self._table_column = None
@@ -2658,6 +2669,11 @@ class ForeignKey(DialectKWArgs, SchemaItem):
parenttable = self.parent.table
+ if self._unresolvable:
+ schema, tname, colname = self._column_tokens
+ tablekey = _get_table_key(tname, schema)
+ return parenttable, tablekey, colname
+
# assertion
# basically Column._make_proxy() sends the actual
# target Column to the ForeignKey object, so the
@@ -2742,13 +2758,30 @@ class ForeignKey(DialectKWArgs, SchemaItem):
"""
+ return self._resolve_column()
+
+ @overload
+ def _resolve_column(self, *, raiseerr: Literal[True] = ...) -> Column[Any]:
+ ...
+
+ @overload
+ def _resolve_column(
+ self, *, raiseerr: bool = ...
+ ) -> Optional[Column[Any]]:
+ ...
+
+ def _resolve_column(
+ self, *, raiseerr: bool = True
+ ) -> Optional[Column[Any]]:
_column: Column[Any]
if isinstance(self._colspec, str):
parenttable, tablekey, colname = self._resolve_col_tokens()
- if tablekey not in parenttable.metadata:
+ if self._unresolvable or tablekey not in parenttable.metadata:
+ if not raiseerr:
+ return None
raise exc.NoReferencedTableError(
"Foreign key associated with column '%s' could not find "
"table '%s' with which to generate a "
@@ -2757,6 +2790,8 @@ class ForeignKey(DialectKWArgs, SchemaItem):
tablekey,
)
elif parenttable.key not in parenttable.metadata:
+ if not raiseerr:
+ return None
raise exc.InvalidRequestError(
"Table %s is no longer associated with its "
"parent MetaData" % parenttable
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 390e23952..0400ab3fe 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -235,7 +235,7 @@ def find_left_clause_to_join_from(
if set(f.c).union(s.c).issuperset(cols_in_onclause):
idx.append(i)
break
- elif Join._can_join(f, s) or onclause is not None:
+ elif onclause is not None or Join._can_join(f, s):
idx.append(i)
break