【问题标题】:SQLAlchemy - Eager load subquery as column for an ORM classSQLAlchemy - 渴望加载子查询作为 ORM 类的列
【发布时间】:2021-12-03 01:02:54
【问题描述】:

我有两张桌子。一个被映射为 ORM 类,如下所示:

from typing import Union
from dataclasses import dataclass
from api.models import db, SerializerMixin

@dataclass
class Company(db.Model, SerializerMixin):
    __tablename__ = "Company"
    company_id: int = db.Column(db.Integer, primary_key = True)
    name: str = db.Column(db.String(50), nullable = False, unique = True)
    primary_contact: Union[int, None] = db.Column(db.Integer, db.ForeignKey("User.user_id"))
    website: Union[str, None] = db.Column(db.Text)

第二个写成一个普通的SQL表(这样写是因为我不打算直接从这个表中查询,只用于JOINS和COUNTS):

user_company_table = db.Table("UserCompany",
    db.Column("user_id", db.Integer, db.ForeignKey("User.user_id"), primary_key = True, unique = True),
    db.Column("company_id", db.Integer, db.ForeignKey("Company.company_id"), primary_key = True),
    db.Column("assigned", db.DateTime, server_default = text("CURRENT_TIMESTAMP"), onupdate = datetime.utcnow),
    db.Column("approved", db.Boolean, nullable = False, default = False)
)

我需要从 Company 获取所有列,同时获取具有 approved = true 并分配给一个特定公司的所有用户的 COUNT。生成的 SQL 如下所示:

SELECT Company.company_id, Company.name, Company.primary_contact, Company.website, (SELECT COUNT(1) FROM UserCompany WHERE approved = true and company_id = Company.company_id) AS user_count FROM Company;

这应该给我这个示例结果:

所以user_count 是来自附加到公司表的子查询的结果集。我将如何向 Company 类添加 user_count 属性,以便在我运行 Company.query.all() 时急切加载此子查询并将结果作为列附加?

注意事项: 使用 Flask 2.0+、Flask-SQLAlchemy、Python 3.9(解释了模型属性中的 @dataclass 和类型提示)

【问题讨论】:

    标签: python mysql flask sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我认为您可以为此使用correlated subquery relationship hybrid

    class Company:
      ...
    
      @hybrid_property
      def user_count(self):
        return db.session.query(user_company_table)\
          .filter_by(company_id=self.id, approved=True)\
          .count()
    
      @user_count.expression
      def user_count(cls):
        return select(func.count(1))\
          .where(user_company_table.c.company_id==cls.id)\
          .where(user_company_table.c.approved==True)\
          .label('user_count')
    

    您甚至可以选择带有标量子查询的非常短的 column_property:https://docs.sqlalchemy.org/en/14/orm/mapped_sql_expr.html#using-column-property

    【讨论】:

    • @hybrid_property 并不是我想要的,但 @column_property 正是我想要的:将子查询映射到列。像魅力一样工作!不敢相信我在文档中错过了这个。 SQLAlchemy 开发人员应该更新文档,这样我就不会那么容易迷失在那里
    猜你喜欢
    • 2014-12-15
    • 2011-07-20
    • 2014-03-13
    • 2021-09-21
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 2020-12-05
    • 1970-01-01
    相关资源
    最近更新 更多