繁体   English   中英

在运行时更改 SqlAlchemy 声明性模型表架构

[英]Change SqlAlchemy declarative model table schema at runtime

我正在尝试构建一个在 postgres 和 sqlite 中运行的声明表。 表之间的唯一区别是 postgres 表将在特定模式中运行,而 sqlite 表不会。 到目前为止,我已经使用下面的代码在没有架构的情况下构建了表。

metadata = MetaData()

class Base(object):

    __table_args__ = {'schema': None}

Base = declarative_base(cls=Base, metadata=metadata)


class Configuration(Base):
    """
        Object representation of a row in the configuration table
    """

    __tablename__ = 'configuration'

    name = Column(String(90), primary_key=True)
    value = Column(String(256))

    def __init__(self, name="", value=""):
        self.name = name
        self.value = value


def build_tables(conn_str, schema=None):

    global metadata

    engine = create_engine(conn_str, echo=True)

    if schema:
        metadata.schema=schema

    metadata.create_all(engine)

但是,每当我尝试在 build_tables() 中设置架构时,该架构似乎都没有在新建的表中设置。 只有当我最初在metadata = MetaData(schema='my_project')处设置架构时,它似乎才起作用,在我知道将运行哪个数据库之前我不想这样做。

是否有另一种使用声明性模型动态设置表模式的方法? 更改元数据是错误的方法吗?

尽管这不是您正在寻找的 100% 的答案,但我认为 @Ilja Everilä 是正确的答案部分在https://stackoverflow.com/a/9299021/3727050 中

我需要做的是将模型“复制”到新的 declarative_base。 结果,我遇到了与您类似的问题:我需要:

  1. 将我的模型的基类更改为新的 Base
  2. 事实证明,我们还需要更改模型的自动生成的__table__属性以指向新的元数据。 否则我在该表中查找 PK 时会遇到很多错误

似乎对我有用的解决方案是通过以下方式克隆模式:

def rebase(klass, new_base):
    new_dict = {
        k: v
        for k, v in klass.__dict__.items()
        if not k.startswith("_") or k in {"__tablename__", "__table_args__"}
    }
    # Associate the new table with the new metadata instead
    # of the old/other pool
    new_dict["__table__"] = klass.__table__.to_metadata(new_base.metadata)

    # Construct and return a new type
    return type(klass.__name__, (new_base,), new_dict)

在您的情况下,这可以用作:

...
# Your old base
Base = declarative_base(cls=Base, metadata=metadata)

# New metadata and base
metadata2 = MetaData(schema="<new_schema>")
Base2 = declarative_base(cls=Base, metadata=metadata)

# Register Model/Table in the new base and meta
NewConfiguration = rebase(Configuration, Base2)
metadata2.create_all(engine)

注意/警告:

  • 以上代码未经测试
  • 在我看来,它过于冗长和笨拙......必须有一个更好的解决方案来满足您的需求(也许通过 Pool 配置?)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM