Home > Mobile >  SQLAlchemy: ForeignKey across schemas
SQLAlchemy: ForeignKey across schemas

Time:11-05

In my postgres server we have a database database with 2 schemas: public and api. public has several tables, and I need to create a table in api with a foreign key to a table in public called model. So it's:

-Schemas
--public
---tables
----models
--api
---tables

Using SQLAlchemy I have the following class:

from sqlalchemy import create_engine, MetaData, Table, Column

class __PostgresService:
  def __init__(self):
    self.__client = create_engine("postgresql://postgres@localhost:5432/database")
    metadata = MetaData(self.__client, schema="public")
    self.__table = Table("training", metadata,
                         Column("id", String, primary_key=True, nullable=False),
                         Column("model_id", ForeignKey("model.id"), nullable=False),
                         schema="api")
    metadata.create_all()

postgres_service = __PostgresService()

However upon launch I receive the following error:

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'training.model_id' could not find table 'public.model' with which to generate a foreign key to target column 'id'

It seems it does look for the correct thing but can't find it? I'm very confused as to why this is happening, especially because the error refers to not finding "public", which is created by default by postgres, rather than "api" which I created myself in pgAdmin. Am I missing some cruicial config?

CodePudding user response:

The error you are getting means that you are trying to create a foreign key referencing a table that SQLAlchemy does not know about. You can tell sqlalchemy about it by creating a Table associated with the same MetaData describing the referenced table. You can also do this using sqlalchemy's reflection capabilities. For example:

from sqlalchemy import create_engine, MetaData, Table, Column
    
class __PostgresService:
    def __init__(self):
        self.__client = create_engine("postgresql://postgres@localhost:5432/database")
        metadata = MetaData(self.__client, schema="public")
        metadata.reflect(schema="public", only=["model"])
        self.__table = Table("training", metadata,
                Column("id", String, primary_key=True, nullable=False),
                Column("model_id", ForeignKey("model.id"), nullable=False),
                schema="api")
        metadata.create_all()

        postgres_service = __PostgresService()

By default, MetaData.create_all() will check for the existence of tables first, before creating them, but you can also specify the exact tables to create: metadata.create_all(tables=[self.__table])

  • Related