我有下面的脚本,如果我的数据库中还不存在3个表,它会尝试创建3个表。
我使用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'
我希望第一个表的主键(trade_id(在其他两个表中充当外键。
我还看到了构建表的其他方法,主要是与Flask相结合,它们创建Model类的子类并在那里填写表的详细信息,构建这样的小型数据库应用程序的更正确方法是什么?
主键出现问题是因为MetaData
对象是一系列表的存储对象。当定义外键时,它会查找要映射到的相关表的MetaData
对象。当您在不同的创建函数中重新定义MetaData
对象时,它们都存储在不同的MetaData
对象中。因此,在创建与第一个表有关系的第二个表期间,无法查找外键。
解决方案是定义一次MetaData
对象,并将每个Table
对象引用到此MetaData
对象。
有关此方面的详细信息,请参阅使用数据库元数据。
此外,您不必在每个创建函数中调用create_all
,但它可以在__init__
结束时调用一次。
关于不同方法的最后一个问题是,您的方法主要是SQLAlchemyCore。当使用Base
的子类时,您将进入SQLAlchemy ORM。这里对差异进行了更多的解释:SQLAlchemyCore和ORM之间的区别是什么