如何解决SQLAlchemy 尝试添加外键时出错
我有以下脚本,如果它们在我的数据库中尚不存在,它会尝试创建 3 个表。
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),Column('underlying_price',FLOAT(2),Column('iv_rank',SMALLINT(),Column('strategy',VARCHAR(20),Column('quantity',Column('expiration_date',Column('option_types',JSON()),Column('strikes',JSON(),Column('premium',Column('prob_of_profit',Column('margin',Column('notes',TEXT()))
Meta.create_all()
def create_closings_table(self):
Meta = MetaData(self.engine)
self.closings = Table(
'closings',Column('id',# FOREIGN KEY - fk_closings_Trade_id
Column('Trade_id',ForeignKey('openings.Trade_id')),Column('closed_at',TEXT()),)
Meta.create_all()
def create_adjustments_table(self):
Meta = MetaData(self.engine)
self.adjustments = Table(
'adjustments',# FOREIGN KEY - fk_adj_Trade_id
Column('Trade_id',Column('adjusted_at',SMALLINT()),FLOAT(2)),DATE()),)
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'
我希望第一个表的主键 (Trade_id) 作为其他两个表的外键。
我也看到过其他的建表方式,主要是结合Flask,创建Model类的子类并在那里填写表的详细信息,构建小型数据库应用程序的更正确方法是什么像这样吗?
解决方法
发生主键问题是因为 MetaData
对象是一系列表的存储对象。在定义外键时,它会查看要映射到的相关表的 MetaData
对象。当您在不同的创建函数中重新定义 MetaData
对象时,它们都存储在不同的 MetaData
对象中。因此,在创建与第一个表相关的第二个表期间无法查找外键。
解决方案是定义一次 MetaData
对象,并将每个 Table
对象引用到此 MetaData
对象。
有关这方面的更多信息,请参阅 Working with Database Metadata。
此外,您不必在每个创建函数中都调用 create_all
,但可以在 __init__
的末尾调用一次。
关于您关于不同方法的最后一个问题是您的方法主要是 SQLAlchemy Core。使用 Base
的子类时,您将进入 SQLAlchemy ORM。这里稍微解释一下差异:What is the difference between SQLAlchemy Core and ORM
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。