Core SqlAlchemy 1.4 string assigned FK raises NoReferencedColumnError in mutli model testing

Viewed 25

I ask for your help in a rather simple situation: SQLA raises NoReferencedColumnError in case of assigning column ForeignKey as a string.

My environment:

  • Ubuntu 22.04
  • SqlAlchemy 1.4.41
  • Python 3.10.4
  • Postgresql 13

There are 2 related tables:

user/models.py

metadata = MetaData(schema=settings.DB_SCHEMA)

user = Table(
    "user", metadata,
    Column("user_id", Integer, primary_key=True, autoincrement=True),
    Column("password", String),
)

and

session/models.py


session = Table(
    "session", metadata,
    Column("session_id", String, primary_key=True)
    Column("user_id", Integer, ForeignKey(f"{settings.DB_SCHEMA}.user.user_id", ondelete="CASCADE", onupdate="CASCADE"), nullable=True,  index=True), 
)

For pytest testing I prepare conftest.py:

from user.models import metadata as user_metadata  
from sessions.models import metadata as session_metadata

engine = create_engine(DB_URL, echo=echo, echo_pool=False)

with engine.connect as conn:
    with conn.begin():
        session_metadata.create_all(conn)
        user_metadata.create_all(conn)

The error sump is as following:

tests/conftest.py:55: in db_init
    session_metadata.create_all(conn)
.venv/lib/python3.10/site-packages/sqlalchemy/sql/schema.py:4917: in create_all
    bind._run_ddl_visitor(
.venv/lib/python3.10/site-packages/sqlalchemy/engine/base.py:2211: in _run_ddl_visitor
    visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
.venv/lib/python3.10/site-packages/sqlalchemy/sql/visitors.py:524: in traverse_single
    return meth(obj, **kw)
.venv/lib/python3.10/site-packages/sqlalchemy/sql/ddl.py:827: in visit_metadata
    collection = sort_tables_and_constraints(
.venv/lib/python3.10/site-packages/sqlalchemy/sql/ddl.py:1291: in sort_tables_and_constraints
    dependent_on = fkc.referred_table
.venv/lib/python3.10/site-packages/sqlalchemy/sql/schema.py:3833: in referred_table
    return self.elements[0].column.table
.venv/lib/python3.10/site-packages/sqlalchemy/util/langhelpers.py:1113: in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
.venv/lib/python3.10/site-packages/sqlalchemy/sql/schema.py:2519: in column
    return self._resolve_column()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = ForeignKey('public.user.user_id'), raiseerr = True

    def _resolve_column(self, raiseerr=True):
    
        if isinstance(self._colspec, util.string_types):
    
            parenttable, tablekey, colname = self._resolve_col_tokens()
    
            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 "
                    "foreign key to target column '%s'"
                    % (self.parent, tablekey, colname),
                    tablekey,
E                   sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'session.user_id' could not find table 'public.user' with which to generate a foreign key to target column 'user_id'

.venv/lib/python3.10/site-packages/sqlalchemy/sql/schema.py:2530: NoReferencedTableError

Using user.c.user_id instead of 'user.user_id' solves the problem, but I'd prefer to find the reason of this failure.

And one more. Initially I tried this code without schema definition, but added schema later according to solutions found here at Stackoverflow. Didn't help :(

Thank you

1 Answers

I've asked the same questions at the SLQA discussion grounds. The only way is to use the column object ref user.c.user_id or a common metadata instance for all the models.

Related