简体   繁体   中英

Sqlalchemy utilize foreign key in table creation

I've began learning sqlalchemy and the script below shows how far I've gotten. I've created a class to start the database, a class that creates a table containing games and their ID's and a class that is used to create tables for each individual external data source.

I realized I need to incorporate foreign keys but upon doing so I get the error below. It's very confusing because I'm fairly certain the MLBGamelist table was created. Any help on this wuld be greatly appreciated.

sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'CaesarsGamelist.game_ref' could not find table 'MLBGamelist' with which to generate a foreign key to target column 'game_ref'
class DBControl:
    def __init__(self,mem):
        print('>>>> [MAIN]: INITIALIZING MAIN DATABASE CONNECTION')
        self.engine = create_engine(memory[mem], echo=False)
        self.inspector = inspect(self.engine)
        self.db_connection = self.engine.connect()
        self.create_session = sessionmaker(bind=self.engine)


class GamelistMLBControl:
    def __init__(self,book,db_control):
        self.table_name = f'{book}Gamelist'
        self.db_control = db_control
            
    def commit_entry(self,site_data):
        write_session = scoped_session(self.db_control.create_session)
        insert_stmt = insert(self.check_table()).values(site_data)
        write_session.execute(insert_stmt)
        write_session.commit()
        write_session.remove()

    def check_table(self):
        metadata = MetaData(bind=self.db_control.engine)
        if self.table_name not in self.db_control.inspector.get_table_names():
            table_name = Table(
                str(self.table_name),
                metadata,
                Column("event_id", Integer, primary_key=True),
                Column("game_ref", String),
                Column("game_datetime", Integer),
                Column("book", String),
            )
    
            metadata.create_all(self.db_control.db_connection)
            print(f'> [{self.table_name}]: Table created')
        else:
            metadata.reflect(self.db_control.engine)
            print(f'> [{self.table_name}]: Table exists')

        return Table(table_name, metadata, autoload=True)

    
class GamelistControl:
    def __init__(self,book,db_control):
        self.table_name = f'{book}Gamelist'
        self.db_control = db_control
            
    def commit_entry(self,site_data):
        write_session = scoped_session(self.db_control.create_session)
        insert_stmt = insert(self.check_table()).values(site_data)
        write_session.execute(insert_stmt)
        write_session.commit()
        write_session.remove()

    def check_table(self):
        metadata = MetaData(bind=self.db_control.engine)
        if self.table_name not in self.db_control.inspector.get_table_names():
            table_name = Table(
                str(self.table_name),
                metadata,
                Column("event_id", Integer, primary_key=True),
                Column("game_ref", String, ForeignKey('MLBGamelist.game_ref')),
                Column("game_datetime", Integer, ForeignKey('MLBGamelist.game_datetime')),
                Column("book", String),
            )
    
            metadata.create_all(self.db_control.db_connection)
            print(f'> [{self.table_name}]: Table created')
        else:
            metadata.reflect(self.db_control.engine)
            print(f'> [{self.table_name}]: Table exists')

        return Table(table_name, metadata, autoload=True)

SQLAlchemy stores details of tables in MetaData objects when a table is created or reflected. Binding an engine to a MetaData object does not in itself cause any table details to be stored. In the code in the question, each class creates a separate MetaData instance, hence the error occurs because the Metadata instance created in GamelistControl doesn't have details of the table created in GamelistMLBControl .

To solve the problem, either call metadata.reflect() after creating the MetaData instance in GamelistControl or create a single MetaData as an attribute of DBControl and use that to create tables in both classes.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM