首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >尝试添加外键时出现SQLAlchemy错误

尝试添加外键时出现SQLAlchemy错误
EN

Stack Overflow用户
提问于 2021-06-30 01:24:52
回答 1查看 69关注 0票数 0

我有以下脚本,试图创建3个表,如果他们还不存在于我的数据库中。

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

代码语言:javascript
运行
复制
    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()

此代码会生成以下错误:

代码语言:javascript
运行
复制
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'

我希望第一个表(trade_id)的主键作为其他两个表中的外键。

我还看到了其他构建表的方法,主要是与Flask相结合,这些方法创建了Model类的子类并填充了表的详细信息,那么构建像这样的小型数据库应用程序更正确的方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-07-01 02:48:44

主键出现问题是因为MetaData对象是一系列表的存储对象。在定义外键时,它在MetaData对象中查找要映射到的相关表。当您在不同的创建函数中重新定义MetaData对象时,它们都存储在不同的MetaData对象中。因此,在创建与第一个表有关系的第二个表期间,不能查找外键。

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

有关这方面的更多信息,请参见Working with Database Metadata

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

关于你关于不同方法的最后一个问题是,你的方法主要是SQLAlchemy核心。当使用Base的子类时,您就进入了SQLAlchemy对象模型。这里更详细地解释了其中的区别:What is the difference between SQLAlchemy Core and ORM

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68183161

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档