SQLAlchemy 尝试添加外键时出错

SQLAlchemy Error Trying To Add Foreign Key

我有以下脚本,它会尝试创建 3 个 table,如果它们不存在于我的数据库中。

我正在使用 MySQL 作为数据库引擎。

    class Journal:
        USER = '******'
        PASSWORD = '******'
        HOST = '******'
        DB_NAME = 'trades_test'
    
        def __init__(self):
            self.engine = create_engine(
                f'mysql+mysqlconnector://{self.USER}:{self.PASSWORD}@{self.HOST}/{self.DB_NAME}'
            )
            self.create_openings_table()
            self.create_closings_table()
            self.create_adjustments_table()
    
        def create_openings_table(self):
            meta = MetaData(self.engine)
            self.openings = Table(
                'openings',
                meta,
                Column('trade_id',
                       INTEGER(unsigned=True),
                       primary_key=True,
                       autoincrement=True),
                Column('opened_at', DATE(), nullable=False),
                Column('underlying', VARCHAR(5), nullable=False),
                Column('underlying_price', FLOAT(2), nullable=False),
                Column('iv_rank', SMALLINT(), nullable=False),
                Column('strategy', VARCHAR(20), nullable=False),
                Column('quantity', SMALLINT(), nullable=False),
                Column('expiration_date', DATE(), nullable=False),
                Column('option_types', JSON()),
                Column('strikes', JSON(), nullable=False),
                Column('premium', FLOAT(2), nullable=False),
                Column('prob_of_profit', FLOAT(2), nullable=False),
                Column('margin', FLOAT(2), nullable=False),
                Column('notes', TEXT()))
            meta.create_all()
    
        def create_closings_table(self):
            meta = MetaData(self.engine)
            self.closings = Table(
                'closings',
                meta,
                Column('id',
                       INTEGER(unsigned=True),
                       primary_key=True,
                       autoincrement=True),
                # FOREIGN KEY - fk_closings_trade_id
                Column('trade_id', ForeignKey('openings.trade_id')),
                Column('closed_at', DATE(), nullable=False),
                Column('underlying_price', FLOAT(2), nullable=False),
                Column('iv_rank', SMALLINT(), nullable=False),
                Column('premium', FLOAT(2), nullable=False),
                Column('margin', FLOAT(2), nullable=False),
                Column('notes', TEXT()),
            )
            meta.create_all()
    
        def create_adjustments_table(self):
            meta = MetaData(self.engine)
            self.adjustments = Table(
                'adjustments',
                meta,
                Column('id',
                       INTEGER(unsigned=True),
                       primary_key=True,
                       autoincrement=True),
                # FOREIGN KEY - fk_adj_trade_id
                Column('trade_id', ForeignKey('openings.trade_id')),
                Column('adjusted_at', DATE(), nullable=False),
                Column('underlying_price', FLOAT(2), nullable=False),
                Column('iv_rank', SMALLINT(), nullable=False),
                Column('quantity', SMALLINT()),
                Column('premium', FLOAT(2)),
                Column('option_types', JSON()),
                Column('strikes', JSON()),
                Column('expiration_date', DATE()),
                Column('margin', FLOAT(2)),
                Column('notes', TEXT()),
            )
            meta.create_all()

此代码产生此错误:

Traceback (most recent call last):
  File "/Users/or/Desktop/Or/Options/journal/journal.py", line 105, in <module>
    Journal()
  File "/Users/or/Desktop/Or/Options/journal/journal.py", line 16, in __init__
    self.create_closings_table()
  File "/Users/or/Desktop/Or/Options/journal/journal.py", line 61, in create_closings_table
    meta.create_all()
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/sql/schema.py", line 4744, in create_all
    bind._run_ddl_visitor(
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 3008, in _run_ddl_visitor
    conn._run_ddl_visitor(visitorcallable, element, **kwargs)
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2016, in _run_ddl_visitor
    visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/sql/visitors.py", line 483, in traverse_single
    return meth(obj, **kw)
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 822, in visit_metadata
    collection = sort_tables_and_constraints(
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/sql/ddl.py", line 1286, in sort_tables_and_constraints
    dependent_on = fkc.referred_table
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/sql/schema.py", line 3671, in referred_table
    return self.elements[0].column.table
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py", line 1093, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/Users/or/opt/anaconda3/lib/python3.8/site-packages/sqlalchemy/sql/schema.py", line 2376, in column
    raise exc.NoReferencedTableError(
sqlalchemy.exc.NoReferencedTableError: Foreign key associated with column 'closings.trade_id' could not find table 'openings' with which to generate a foreign key to target column 'trade_id'

我希望第一个 table (trade_id) 的主键用作其他两个 table 的外键。

我还看到了其他构造 table 的方法,主要是结合 Flask,创建模型 class 的子 class 并填写详细信息table 那里,构建这样一个小型数据库应用程序的更正确方法是什么?

主键出现问题是因为 MetaData 对象是一系列 table 的存储对象。定义外键时,它会查看 MetaData 对象,以便将相关的 table 映射到。当您在不同的创建函数中重新定义 MetaData 对象时,它们都存储在不同的 MetaData 对象中。因此,在创建与第一个 table.

相关的第二个 table 期间无法查找外键

解决方案是定义一次MetaData对象,然后将每个Table对象引用到这个MetaData对象。

有关此的更多信息,请参阅 Working with Database Metadata

此外,您不必在每个创建函数中都调用 create_all,但可以在 __init__ 结束时调用一次。

关于你最后一个关于不同方法的问题,你的方法主要是SQLAlchemy Core。使用 Base 的子类时,您将进入 SQLAlchemy ORM。这里对差异进行了更多解释:What is the difference between SQLAlchemy Core and ORM