过滤列表中的 Django JSONB 项目

Raz*_* B. 6 django postgresql jsonb

我有一个 Django dataJSONField,其中包含以下数据

{
    "title": "Some Title",
    "projects": [
        {"name": "Project 1", "score": "5"},
        {"name": "Project 2", "score": "10"},
        {"name": "Project 3", "score": "2"},
    ]
}
Run Code Online (Sandbox Code Playgroud)

我需要按项目分数(数字类型)过滤行,即where project -> score <= 5

Django ORM 提供了过滤和使用 Postgres JSONB 字段的基础知识。也就是说,我可以做

Model.objects.filter(data__title="Some Title")
Run Code Online (Sandbox Code Playgroud)

但是当 JSON 列中有一个项目列表时,事情就不那么简单了,即我不能这样做

Model.objects.filter(data__projects__score__lte=5)

Only way I can reach the `score` in Django ORM is to use the array index, i.e.

Model.objects.filter(data__projects__0__score__lte=5)
Run Code Online (Sandbox Code Playgroud)

但这现在不起作用,我对该列表中的所有项目感兴趣,无论数量多少

我目前所在的位置:

我已将该列表作为查询集加入jsonb_array_elements

queryset.query.join(join=join_cfg)
Run Code Online (Sandbox Code Playgroud)

将以下 sql 附加到 QUERY

LEFT JOIN LATERAL jsonb_array_elements("my_table"."data" -> 'projects') projects ON TRUE
Run Code Online (Sandbox Code Playgroud)

现在,在原始 SQL 中,我可以执行类似的操作来过滤该列表

WHERE (projects->>'score')::numeric < 5
Run Code Online (Sandbox Code Playgroud)

问题是我无法让它与 Django ORM 很好地配合

目前,我正在WHERE使用添加此子句queryset.extra()

queryset = queryset.extra(where=where_clause)
Run Code Online (Sandbox Code Playgroud)

问题在于,通过使用.extra(),WHERE 子句会AND在查询末尾进行编辑,这与使用 Django 对象完成的其他过滤器结合使用会产生意外的结果Q

即生成的最终 WHERE 子句如下所示:

WHERE condition1 AND (condition2 OR condition3) AND MY_CUSTOM_WHERE_CONDITION

// but what I need is 

WHERE condition1 AND (condition2 OR condition3 OR MY_CUSTOM_WHERE_CONDITION)
Run Code Online (Sandbox Code Playgroud)

理想情况下,这个自定义条件应该添加一个Q对象,即

query_filters |= Q(projects__score__lte=5)
Run Code Online (Sandbox Code Playgroud)

但是由于该projects列是自定义连接, Cannot resolve keyword 'projects' into field.所以我无法使用 django ORM 来过滤,就像我title在本文开头过滤的方式一样


我认为这个自定义连接必须以某种方式进行注释,然后Q在该注释列上使用该对象,但我无法让它工作。

我已经尝试过,额外的选择、RawSQL 注释、FilteredRelation 等等。

任何帮助表示赞赏。谢谢