【问题标题】:Chained comparisons in SQLAlchemySQLAlchemy 中的链式比较
【发布时间】:2012-09-05 15:53:51
【问题描述】:

Python supports chained comparisons: 1 < 2 < 3 转换为 (1 < 2) and (2 < 3)。

我正在尝试使用 SQLAlchemy 进行 SQL 查询,如下所示:

results = session.query(Couple).filter(10 < Couple.NumOfResults < 20).all()

我得到的结果并不像预期的那样。我已经打开了引擎的 echo=True 关键字,并且确实 - 生成的 SQL 查询只包含两个比较之一。

我找不到任何明确说明这是禁止的文档。我假设如果 Python 支持这种类型的表达式,那么 SQLAlchemy 也应该支持它。

为什么这不起作用?我想到了一种可能的解决方案(在答案中分享),但很高兴听到其他意见。

【问题讨论】:

标签: python database orm sqlalchemy


【解决方案1】:

SQLAlchemy 不支持 Python 的链式比较。以下是作者 Michael Bayer 的官方原因:

不幸的是,从 python 的角度来看,这可能是不可能的。 “x BETWEEN 部分,要完成这项工作,需要根据比较运算符的方向对BinaryExpression 对象的__nonzero__() 值进行操作,以便强制进行两个比较。将基本的__nonzero__() 添加到返回 False 的 BinaryExpression 说明当前代码库对它的容忍度非常差,并且至少需要将数十种“if x:”类型的检查转换为“if x is None: ",但可能还有其他更难以解决的问题。对于外界来说,它可能会造成严重破坏。 鉴于此处适当的 SQL 运算符是 BETWEEN ,可以从 between 运算符轻松访问,我不认为向后弯腰和混淆人们的水平是值得的,所以这是一个“不会修复”。

详情请见: https://bitbucket.org/zzzeek/sqlalchemy/issues/1394/sql-expressions-dont-support-x-col-y

【讨论】:

    【解决方案2】:

    原因是 Python 实际上会计算类似于以下内容的内容:

    _tmp = Couple.NumOfResults
    (10 < _tmp and _tmp < 20)
    

    SQLAlchemy 不支持 and 运算符(应该改用 and_)。因此,SQLAlchemy 中不允许进行链式比较。

    在原始示例中,应该改为编写以下代码:

    results = session.query(Couple).filter(and_(10 < Couple.NumOfResults, 
                                                Couple.NumOfResults < 20)).all()
    

    【讨论】:

    • 完全正确。在 python 中,a &gt; b &gt; c 是特殊语法。 3 &gt; 2 &gt; 1 是 True,而 (3 &gt; 2) &gt; 1 是 False。如果没有关于您的代码的解析器级信息,sqlalchemy 无法在这两种情况下直观地表现。
    • 完全错了。在链式比较中,Python 保证 not 计算 Couple.NumOfResults 两次。
    猜你喜欢
    • 1970-01-01
    • 2014-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-10
    • 1970-01-01
    相关资源
    最近更新 更多