我试图运行一个查询,该查询根据字典列表过滤结果。

让我们更清楚...

我有一个表标题,每个标题都有一个版本字段

class Heading(Base):
    id = Column(Integer, primary_key=True)
    name = Column(String(50), nullable=False)
    version = Column(Integer)


另一方面,我有一个像这样的字典列表(Json格式):

"headings": [
    {
        "id": 1,
        "version": 1
    },
    {
        "id": 2,
        "version": 1
    }
]


我想在标题表上执行查询,该查询排除数据库中版本等于(json)列表中版本的行。

我试着执行这样的事情:

res = Heading.query.filter(~Heading.id.in_([d['id'] for d in headings if d['version'] == Heading.version])).all()


使用如下所示的数据库(Json再次格式化,对不起):

[
{
    "id": 1,
    "name": "Heading1",
    "version": 2,
},
{
    "id": 2,
    "name": "Heading2",
    "version": 1,
}
]


但是无论如何它都会返回Heading2行。基本上,我希望查询返回Json中未定义的所有行以及数据库中具有较新版本的行。

我不知道我的问题是否足够清楚。
也许这不是正确的方法,请让我知道

预先感谢您的任何帮助

编辑:
生成的Raw SQL是这样的:

SELECT heading.id, heading.name, heading.version
FROM heading
WHERE heading.id = heading.id


因此,sqlalchemy查询存在明显问题,但我无法弄清楚是什么...

我认为它来自零件

if d['version'] == Heading.version


但是我不知道如何在查询的其他地方重新构造这种条件

最佳答案

您怀疑问题出在

[... for ... if d['version'] == Heading.version]


尽管d['version'] == Heading.version产生一个SQL表达式对象,但是Python然后使用其真实值进行过滤:

In [9]: bool(headings[0]['version'] == Heading.version)
Out[9]: False


因此您的列表理解会导致一个空列表。 Heading.id永远不能在空列表中,因此

~Heading.id.in_([])


将简单地评估为true:

In [10]: print(~Heading.id.in_([]))
1 = 1


鉴于您的数据库支持composite IN queries,解决方案是将其与(id,版本)元组进行比较:

In [9]: from sqlalchemy import tuple_

In [10]: session.query(Heading).\
    ...:     filter(~tuple_(Heading.id, Heading.version).in_(
    ...:         [(d['id'], d['version']) for d in headings])).\
    ...:     all()
Out[10]: [<__main__.Heading at 0x7f840cc8ae48>]

In [11]: _[0].name
Out[11]: 'Heading1'

09-11 19:21
查看更多