【问题标题】:Change SqlAlchemy declarative model table schema at runtime在运行时更改 SqlAlchemy 声明性模型表架构
【发布时间】:2018-04-05 13:59:48
【问题描述】:

我正在尝试构建一个在 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') 时,它似乎才有效,在我知道我将运行哪个数据库之前我不想这样做。

还有其他方法可以使用声明性模型动态设置表架构吗?更改元数据是错误的方法吗?

【问题讨论】:

  • 相关,如果不重复:stackoverflow.com/questions/9298296/…
  • @IljaEverilä 在您引用的问题中接受的答案是暗示该问题的 OP 所说的确切内容不起作用。很难看出这怎么可能是重复的。
  • 这是一个很好的问题,也是谷歌为数不多的(如果不是唯一的)结果之一。在尝试在不同应用程序之间重用模型时,我遇到了类似的情况。我需要替换 Base tho 并尝试动态创建新类型。你找到答案了吗?

标签: python sqlalchemy


【解决方案1】:

尽管这不是您正在寻找的 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)

注意事项/警告:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 2013-11-26
    相关资源
    最近更新 更多