Flask SQLAlchemy如何基于child2和child3子表name字段对父表排序
问题根因
你定义的expression方法中使用的Python原生if判断是在代码定义阶段就执行完成的,并不会被编译为SQL层面的行级判断逻辑。cls.child2Id是SQLAlchemy的列对象,永远不会等于Python的None,所以你的表达式永远只会返回child3的子查询,自然无法得到预期排序结果。
正确实现
实例层面的hybrid_property逻辑无需修改,仅需调整expression部分,使用SQL原生的条件判断逻辑即可,这里推荐用COALESCE函数实现(会返回第一个非空参数,刚好匹配你业务中child2、child3同一时间仅一个有值的场景):
from sqlalchemy import func @hybrid_property def child2Or3Name(self): # 原有实例层面逻辑不变 if self.child2Id is not None: return self.child2.name return self.child3.name @child2Or3Name.expression def child2Or3Name(cls): # 分别定义两个子查询 child2_name = select([Child2Model.name]).where(Child2Model.id == cls.child2Id).as_scalar() child3_name = select([Child3Model.name]).where(Child3Model.id == cls.child3Id).as_scalar() # 取第一个非空的name值 return func.coalesce(child2_name, child3_name)
如果你更偏好显式的条件判断,也可以用CASE语句实现,效果完全一致:
from sqlalchemy import case @child2Or3Name.expression def child2Or3Name(cls): child2_name = select([Child2Model.name]).where(Child2Model.id == cls.child2Id).as_scalar() child3_name = select([Child3Model.name]).where(Child3Model.id == cls.child3Id).as_scalar() return case( (cls.child2Id.is_not(None), child2_name), else_=child3_name )
验证
修改完成后调用原有排序逻辑即可得到预期结果:
Parent.query.order_by(Parent.child2Or3Name).all()
注:如果你使用的是SQLAlchemy 2.0+版本,
select的参数无需用列表包裹,直接写select(Child2Model.name)即可。
内容的提问来源于stack exchange,提问作者Grec Mihai
相关产品推荐
相关产品推荐

