如何在SQLAlchemy查询中使用混合属性实现作业通过状态的判定
如何在SQLAlchemy查询中使用混合属性实现作业通过状态的判定
首先先帮你修正现有代码里的两个小细节,避免后续踩坑:
Homework类里的questions关系,类型标注应该是list["Question"](单数,对应你的Question类名,不是Questions)- 你的
hybrid_property里的question.answered correctly应该是question.answered_correctly(下划线连接,和属性定义保持一致)
接下来回到你的核心问题:实现passed.expression让这个混合属性能在SQL查询中生效。其实你的方向是对的——我们需要把「所有题目都答对」这个逻辑翻译成SQLAlchemy能识别的表达式,和你手写的SQL逻辑对应上就行。
先看你写的找未通过作业的SQL:它的核心是统计当前作业下答错的题目数量,如果数量>0就是未通过。反过来,通过的作业就是答错的题目数量=0,或者等价于「不存在答错的题目」。我们可以用两种方式实现这个逻辑的表达式:
方式一:用EXISTS子查询(推荐,性能更优)
这种方式的逻辑是:如果当前作业不存在任何答错的题目,就判定为通过。代码实现如下:
from sqlalchemy import exists, select class Homework(Base): __tablename__ = 'homework' id: Mapped[int] = mapped_column(primary_key=True) answered_correctly: Mapped["bool"] = mapped_column() # 修正类型标注为list["Question"] questions: Mapped[list["Question"]] = relationship( back_populates="homework", default_factory=list ) @hybrid_property def passed(self): # 修正属性名拼写错误 return all(question.answered_correctly for question in self.questions) @passed.expression def passed(cls): # 子查询:检查当前homework是否存在答错的题目 has_incorrect_question = exists( select(Question.id) .where(Question.homework_id == cls.id) .where(Question.answered_correctly == False) ) # 取反:不存在答错的题目 = 作业通过 return ~has_incorrect_question
方式二:用聚合函数(和你的手写SQL逻辑完全对应)
如果你想和自己写的SQL逻辑更贴近,可以用COUNT+CASE的方式,统计答错的题目数量是否为0:
from sqlalchemy import func, case, select class Homework(Base): # ... 其他代码保持不变 ... @passed.expression def passed(cls): # 统计当前homework下答错的题目数量 incorrect_count = ( select(func.count(case((Question.answered_correctly == False, 1)))) .where(Question.homework_id == cls.id) # 关联外部的Homework表,告诉SQLAlchemy这是关联子查询 .correlate(cls) # 把聚合结果作为标量子查询返回 .scalar_subquery() ) # 答错数量为0则作业通过 return incorrect_count == 0
如何使用这个属性查询
现在你就可以像使用普通字段一样在SQL查询里用passed了:
# 查询所有通过的作业 passed_homeworks = session.query(Homework).filter(Homework.passed == True).all() # 或者查询未通过的作业(和你的手写SQL逻辑完全匹配) failed_homeworks = session.query(Homework).filter(Homework.passed == False).all()
为什么这样写能生效
SQLAlchemy的hybrid_property的expression方法需要返回一个SQL表达式,这个表达式会被自动翻译成对应的SQL语句。比如方式一的~has_incorrect_question会被翻译成NOT EXISTS (SELECT ... FROM questions WHERE ...),和你手写的SQL逻辑完全对齐,查询时就能正确关联Homework和Question表,完成聚合判断。
备注:内容来源于stack exchange,提问作者frimann
相关产品推荐
相关产品推荐

