我需要在 for 循环中的不同位置创建许多类似的数据库。在循环开始时,我将引擎创建到path_sql_db磁盘上的新引擎。
engine = sa.create_engine("sqlite:///{}".format(path_sql_db), echo=0, listeners=[util_sa.ForeignKeysListener()])
Session = sa.orm.sessionmaker(bind=engine)
session = Session()
Run Code Online (Sandbox Code Playgroud)
然后我有几个模块中的表从 DB_Base 继承,它是在外部模块中定义的;
from sqlalchemy.ext.declarative import declarative_base
DB_Base = declarative_base()
Run Code Online (Sandbox Code Playgroud)
问题是在 for 循环的下一次迭代中,我无法创建我的表,因为它们仍然存在于某处?
InvalidRequestError: Table 'vector_var01' is already defined for this MetaData instance.
Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
Run Code Online (Sandbox Code Playgroud)
我试过从引擎 MetaData.drop_all() ;
meta = sa.MetaData(bind = engine)
meta.reflect()
meta.drop_all()
session.close()
Run Code Online (Sandbox Code Playgroud)
也来自基地;
DB_Base.metadata.bind = engine
DB_Base.metadata.reflect()
DB_Base.metadata.drop_all()
Run Code Online (Sandbox Code Playgroud)
没有成功,我仍然只是在这里的黑暗中徘徊。
错误指的是哪个 MetaData 实例?如何完全重置数据库代码的状态?
编辑
好的,我找到了问题所在。我正在尝试动态生成 ORM 表。我正在研究优化程序并将设计空间变量存储在他们自己的表中,每个可能的变量值一行。
导致错误的最小示例;
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
name = Column(String(50))
def generate_variable_table_class(name):
"""This is a helper function which dynamically creates a new ORM enabled class
The table will hold the individual values of each variable
Individual values are stored as a string
"""
class NewTable( Base ):
__tablename__ = "vector_{}".format(name)
id = Column(Integer, primary_key=True)
value = Column(String(16), nullable=False, unique=True)
def __init__(self,value):
self.value = str(value)
def __str__(self):
return self.value
def __repr__(self):
return self.value
NewTable.__name__ = "vector_ORM_{}".format(name)
return NewTable
if __name__ == "__main__":
for name in 'asfd', 'jkl', 'xyz':
print("For loop: ",name)
engine = create_engine(r'sqlite:///c:\testdelete\{}.sql'.format(name))
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
bunch_o_foos = [Foo(name = i) for i in range(10)]
session.add_all(bunch_o_foos)
session.commit()
for foo in bunch_o_foos:
print(foo.id)
variables = [generate_variable_table_class(i) for i in range(10)]
Run Code Online (Sandbox Code Playgroud)
这实际上与这个问题相同;SQLAlchemy 中的动态 Python 类定义。这不可能吗?
作为一个最小的例子:
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Foo(Base):
__tablename__ = 'foo'
id = Column(Integer, primary_key=True)
name = Column(String(50))
for name in 'asfd', 'jkl', 'xyz':
engine = create_engine('sqlite:///{}'.format(name))
Base.metadata.create_all(engine)
Run Code Online (Sandbox Code Playgroud)
运行良好。drop_all意味着删除表,可能不是你想要的。一旦使用,bind您就将元数据对象绑定到该特定引擎。虽然:
Base.metadata.bind = engine
Base.metadata.create_all()
Run Code Online (Sandbox Code Playgroud)
也适用于最小的示例。
编辑
根据示例案例,您收到错误是因为您尝试使用相同的子类定义具有相同表名(例如 vector_0)的类Base,该子MetaData类附加了一个对象,该对象只能具有每个表名。
在新的简单情况下,每个数据库的表之间没有区别,因此您应该将调用移出generate_variable_table_class主循环,并且只进行一次。
如果你有每个数据库的行为,你可以Base每次使用一个新的(即也移动Foo到一个函数中!)(此外,对的调用generate_variable_table_class应该在上面create_all而不是在最后)
即使如此,sqlalchemy 也不喜欢它们都被命名为NewTable。声明性 ORM 会评估您的类定义,因此它会NewTable在您设置__name__之前查看。解决方案是不使用声明性系统(请参阅文档中的“经典映射”)。
但另一种方法是扩展声明性元类来处理名称更改。该declarative_base函数采用显式metaclass参数,因此这似乎在框架的规范范围内。要使用下面的一个,您需要在定义__name__ = "vector_ORM_{}".format(name)中进行设置NewTable。如果您也想真正干净地更新__qualname__,尽管 sqlalchemy 不在任何地方使用它。
Base.metadata.bind = engine
Base.metadata.create_all()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5361 次 |
| 最近记录: |