使用动态映射和复杂对象查询的SQLAlchemy

1 投票
1 回答
2196 浏览
提问于 2025-04-17 09:57

我遇到了以下情况:

class MyBaseClass(object):

    def __init__(self, name):
        self.name = name
        self.period = None
        self.foo = None

    def __getitem__(self, item): 
        return getattr(self, item)

    def __setitem__(self, item, value):
        return setattr(self, item, value)

如果在运行时需要添加一些额外的列,我们可以这样做:

my_base_class_table = Table("MyBaseClass", metadata,
           Column('name', String, primary_key=True),
           Column('period', DateTime),
           Column('foo', Float),
           )


my_base_class_table = Table("MyBaseClass", metadata, extend_existing=True)

column_list = ["value_one", "other_name", "random_XARS123"]

for col in column_list:
    my_base_class_table.append_column(Column(col, Float))

create_all()

mapper(MyBaseClass, my_base_class_table)

到这里为止,我们已经有了一个功能齐全的动态表映射,并且有了扩展的列。

现在,使用sqlalchemy的ORM(对象关系映射),你可以轻松地实例化一个MyBaseClass,并修改它以反映数据库中的变化:

base_class = MyBaseClass(name="Something")
base_class.period = "2002-10-01"

并且可以使用那些列名未知的动态列:

for col in column_list:
    base_class[col] = 10

session.add(base_class)

但实际上只有在你知道列名的情况下

t_query = session.query(func.strftime('%Y-%m-%d', MyBaseClass.period),
                        func.sum(MyBaseClass.foo), \
                        func.sum(MyBaseClass.other_name*MyBaseClass.value_one))

有没有可能在不知道列名的情况下重复最后的查询(t_query)?我已经尝试了不同的情况,但都没有成功:

 func.sum(MyBaseClass[column_list[0]]*MyBaseClass.[column_list[1]])

实际上唯一有效的方法是使用扩展的文本SQL,比如:

 text_query = text("SELECT strftime('%Y-%m-%d', period) as period, sum(foo) as foo, sum({0}*{1}) as bar FROM {2} ".format(column_list[0], column_list[1], "MyBaseClass")

1 个回答

2

简单的 getattr 就能解决这个问题:

t_query = session.query(func.strftime('%Y-%m-%d', getattr(MyBaseClass, "period")),
                        func.sum(getattr(MyBaseClass, "foo")),
                        func.sum(getattr(MyBaseClass, "other_name") * getattr(MyBaseClass, "value_one"))
                        )

撰写回答