gpt4 book ai didi

python - 使用动态表生成完全刷新 SQLAlchemy

转载 作者:太空宇宙 更新时间:2023-11-03 11:03:59 24 4
gpt4 key购买 nike

我需要在 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()

然后我的表在几个模块中继承自在外部模块中定义的 DB_Base;

from sqlalchemy.ext.declarative import declarative_base
DB_Base = declarative_base()

问题是在我的下一次 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.

我已经尝试从引擎中使用 MetaData.drop_all();

meta = sa.MetaData(bind = engine)
meta.reflect()
meta.drop_all()
session.close()

还有来自基地的;

DB_Base.metadata.bind = engine
DB_Base.metadata.reflect()
DB_Base.metadata.drop_all()

没有成功,我仍然只是在黑暗中徘徊。

错误指的是哪个元数据实例?我怎样才能完全重置我的数据库代码的状态?

编辑

好的,我找到了问题所在。我正在尝试动态生成 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)]

其实和这个问题是一样的; Dynamic Python Class Definition in SQLAlchemy .这不可能吗?

最佳答案

作为一个最小的例子:

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)

运行良好。 drop_all 表示删除表,可能不是您想要的。一旦您使用 bind,您就将元数据对象绑定(bind)到该特定引擎。虽然:

Base.metadata.bind = engine
Base.metadata.create_all()

也适用于最小示例。

编辑

根据示例情况,您收到错误是因为您试图使用相同的 Base 子类定义具有相同表名(例如 vector_0)的类,该子类具有 MetaData 对象附加到它,每个表名只能有一个。

  • 在您的新简单案例中,每个数据库的表之间没有区别,因此您应该将对 generate_variable_table_class 的调用移出主循环,并且只调用一次。

  • 如果您有针对每个数据库的行为,您可以每次都使用一个新的 Base(即将 Foo 也移动到一个函数中!)(另外,对 generate_variable_table_class 的调用应该在 create_all 之上,而不是在末尾)

  • 即便如此,sqlalchemy 也不喜欢它们都被命名为 NewTable。声明式 ORM 评估您的类定义,因此它会在您之后设置 __name__ 之前看到 NewTable。一种解决方案是不使用声明式系统(请参阅文档中的“经典映射”)。

  • 但另一种方法是扩展声明性元类以处理名称更改。 declarative_base 函数采用显式 metaclass 参数,因此这似乎在框架规范内。要使用下面的一个,您可以在 NewTable 定义中设置 __name__ = "vector_ORM_{}".format(name)。如果你想真正干净地更新 __qualname__,尽管 sqlalchemy 没有在任何地方使用它。

from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta

class NamingDeclarativeMeta(DeclarativeMeta):
def __init__(cls, classname, bases, dict_):
if '__name__' in cls.__dict__:
cls.__name__ = classname = cls.__dict__['__name__']
DeclarativeMeta.__init__(cls, classname, bases, dict_)

Base = declarative_base(metaclass=NamingDeclarativeMeta)

关于python - 使用动态表生成完全刷新 SQLAlchemy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25119038/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com