【问题标题】:Completely refresh SQLAlchemy with dynamic table generation使用动态表生成完全刷新 SQLAlchemy
【发布时间】:2014-08-05 23:16:18
【问题描述】:

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

没有成功,我仍然只是在这里在黑暗中四处游荡。

错误指的是哪个 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)]

这实际上与这个问题相同; Dynamic Python Class Definition in SQLAlchemy。这不可能吗?

【问题讨论】:

  • 如果您发布了您的创建表代码,将更容易看到您的具体问题。

标签: python sqlalchemy


【解决方案1】:

作为一个最小的例子:

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,您就将元数据对象绑定到该特定引擎。虽然:

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

也适用于最小示例。

编辑

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

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

  • 1234563 @不是最后)
  • 即便如此,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)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-04-07
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-07
    相关资源
    最近更新 更多