【问题标题】:SQLalchemy - Build ORM model from querySQLalchemy - 从查询构建 ORM 模型
【发布时间】:2020-07-20 09:45:51
【问题描述】:

我们有一个使用 sqlalchemy 作为 ORM 的应用程序。除了映射表,我们还使用它来映射现有的数据库视图,效果很好。

但是,我们找不到将自定义查询映射到模型的简单方法。例如,假设我们有这样的报告:

q = session.query(
    Table1.field1, Table2.field2, func.sum(Table2.field3).label('sum')
).join(
    Table2, Table1.id == Table2.id
).filter(
    Table1.field1 == param1, Table1.field2 == param2
).group_by(
    Table1.field1, Table2.field2
) 

我们想将此查询映射到类似的类

class Report(CustomBaseModel):

    field1 = Column(Integer, primary_key=True)
    field2 = Column(Integer, primary_key=True)
    sum = Column(Numeric)

我们的CustomBaseModel 已经实现了很多功能,因此能够在这里使用它会减少代码重复。例如,以这种方式使用声明性基础可以将relationships 定义到其他表。

当然这个例子不起作用,因为数据库中没有可选的"report"

我尝试在 Report 类中设置 __table__ = q.subquery()。通过这种方式查询可以工作,但无法定义列、关系或其他属性。也许有更好的方法来实现这一点。

【问题讨论】:

  • 请查看this answer 使用sqlalchemy-utils 未记录的功能。 它仍然需要您在数据库上创建视图,但这些也应该由(alembic)迁移来处理。
  • 谢谢。但是,由于这些报告涉及复杂的聚合,仅视图方法是不够的。我也考虑过数据库功能,虽然没有简单的方法来映射它们,但我会看看sqlalchemy-utils,看看还有哪些功能可能有用。
  • 你的代码示例是完美的view-able。如果您需要向视图添加过滤器,您可以这样做。然后,您甚至可以让relationships 使用指向具有明确指定 FK 的视图的链接。很想知道你最终得到的解决方案。
  • 我不确定你在这里问什么;究竟是什么问题? 这样查询可以工作,但无法定义列、关系或其他属性:列来自__table__ 命名的查询。您可以添加关系和其他属性就好了。我确实做到了这一点。我们的模型是从另一个模型的子查询中填充的,它具有混合属性、多个关系(在模型和其他模型上定义,指向具有反向引用的特定模型),以及常规方法和属性。
  • 如果您想将列添加到模型中,您必须将它们添加到 查询。您不能在模型本身上添加列,因为没有表可以添加这些列。

标签: python sqlalchemy flask-sqlalchemy


【解决方案1】:

我不太明白你想要实现什么样的行为,在这个例子中,表Report存在但不需要,它是有一些数据以简化方式查询,my_query()和@ 987654323@ 使用将其视为column 的包装器,您在查询中调用函数名称并输出结果。

@hybrid_property 不能不接受 *args**kwargs@hybrid_method 也不会。

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_property, hybrid_method
from sqlalchemy.orm import sessionmaker
import sqlalchemy as sql

Base = declarative_base()
db_uri = 'sqlite:///test.db'
engine = sql.create_engine(db_uri)
Session = sessionmaker(bind=engine)
session = Session()

class Report(Base):
    __tablename__ = 'report'
    id = sql.Column(sql.Integer, primary_key=True)
    name = sql.Column(sql.String(30), default='Unknown')

    @hybrid_property
    def my_query(self):
        return self.name

    @hybrid_method
    def my_query_session(self, _session):
        return _session.query(Report).order_by(
            Report.id.desc()).first().name


if __name__ == '__main__':
    Report.__table__.create(engine)
    session.add(Report(name='Alex'))
    session.add(Report(name='Nata'))
    session.commit()

    query_data = session.query(Report).first()
    print(query_data.my_query)
    print(query_data.my_query_session(session))

【讨论】:

  • 这绝对不是被问到的
猜你喜欢
  • 1970-01-01
  • 2020-12-01
  • 2012-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 2020-05-02
相关资源
最近更新 更多