sqlalchemy运行时实体上的动态模式

时间:2015-04-12 22:03:04

标签: python sqlalchemy postgresql-9.3

我正在使用SQL Alchemy,并且有一些特定于帐户的架构。模式的名称是使用帐户ID派生的,因此在我访问应用程序服务或存储库层之前,我没有模式的名称。我想知道是否可以针对在运行时动态设置其架构的实体运行查询?

我知道我需要设置__table_args__['schema']并尝试使用内置的type(),但我总是收到以下错误:

could not assemble any primary key columns for mapped table

我已经准备好放弃直接编写sql,但我真的很讨厌这样做。知道如何做到这一点?我正在使用SA 0.99而且我确实有PK映射。

由于

4 个答案:

答案 0 :(得分:3)

一种选择是反映特定的帐户相关表。这是关于此事的SqlAlchemy Documentation

或者,您可以使用静态schema属性创建表,并在运行时根据需要更新它并运行您需要的查询。我无法想到这样做的非混乱方式。所以这里是凌乱的选项

每当切换帐户时,使用循环更新每个表定义中的架构属性。

  1. 将所有特定于帐户的表添加到列表中。

    • 如果表以声明性语法表示,则必须修改DeclarativeName.__table__.schema属性。我不确定您是否还需要修改DeclarativeName.__table_args__['schema'],但我想它不会受到伤害。
    • 如果表格以旧样式表语法表示,则必须修改Table.schema属性。
  2. 如果您正在使用任何关系或外键的文本,那么这将会中断,您必须检查每个表格以获取此类硬编码用法并更改它们 示例

    • user_id = Column(ForeignKey('my_schema.user.id'))需要写为user_id = Column(ForeignKey(User.id))。然后,您可以将User的架构更改为my_new_schema。否则,在查询时sqlalchemy将会混淆,因为当查询指向my_schema.user.id时,外键将指向my_new_schema.user
  3. 我不确定在不使用纯文本的情况下是否可以表达更复杂的关系,所以我想这是我提出的解决方案的限制。

  4. 这是我在终端写的一个例子:

    >>> from sqlalchemy import Column, Table, Integer, String, select, ForeignKey
    >>> from sqlalchemy.orm import relationship, backref
    >>> from sqlalchemy.ext.declarative import declarative_base
    >>> B = declarative_base()
    >>> 
    >>> class User(B):
    ...   __tablename__ = 'user'
    ...   __table_args__ = {'schema': 'first_schema'}
    ...   id = Column(Integer, primary_key=True)
    ...   name = Column(String)
    ...   email = Column(String)
    ... 
    >>> class Posts(B):
    ...   __tablename__ = 'posts'
    ...   __table_args__ = {'schema':'first_schema'}
    ...   id = Column(Integer, primary_key=True)
    ...   user_id = Column(ForeignKey(User.id))
    ...   text = Column(String)
    ... 
    >>> str(select([User.id, Posts.text]).select_from(User.__table__.join(Posts)))
    'SELECT first_schema."user".id, first_schema.posts.text \nFROM first_schema."user" JOIN first_schema.posts ON first_schema."user".id = first_schema.posts.user_id'
    >>> account_specific = [User, Posts]
    >>> for Tbl in account_specific:
    ...   Tbl.__table__.schema = 'second_schema'
    ... 
    >>> str(select([User.id, Posts.text]).select_from(User.__table__.join(Posts)))
    'SELECT second_schema."user".id, second_schema.posts.text \nFROM second_schema."user" JOIN second_schema.posts ON second_schema."user".id = second_schema.posts.user_id'
    

    正如您所看到的,在我更新表格的架构属性后,相同的查询引用了second_schema

答案 1 :(得分:3)

它们是静态设置的。外键需要相同的处理,我还有一个问题,因为我有多个包含多个表的模式,所以我这样做了:

<a href=#EditContentModal>

然后在我的启动代码中:

from sqlalchemy.ext.declarative import declarative_base

staging_dbase = declarative_base()
model_dbase = declarative_base()


def adjust_schemas(staging, model):
    for vv in staging_dbase.metadata.tables.values():
        vv.schema = staging
    for vv in model_dbase.metadata.tables.values():
        vv.schema = model


def all_tables():
    return staging_dbase.metadata.tables.union(model_dbase.metadata.tables)

您可以为单个声明性基础修改此内容。

答案 2 :(得分:0)

来自sqlalchemy 1.1, 使用schema_translation_map可以很容易地做到这一点。

https://docs.sqlalchemy.org/en/11/changelog/migration_11.html#multi-tenancy-schema-translation-for-table-objects

答案 3 :(得分:0)

我正在一个项目中,必须在其中动态创建postgres模式和表,然后在适当的模式中插入数据。这是我做过的事,也许会对某人有所帮助:

namespace std_dum
{
    int add(int x, int y);

    int mult(int x, int y);
}

int main()
{
 std::cout << std_dum::add(100, 200) << '\n';
 std::cout << std_dum::mult(100, 200) << '\n';

 return 0;
}

namespace std_dum
{

    int add(int x, int y)
    {
        return x + y;
    }

    int mult(int x, int y)
    {
        return x * y;
    }

 }