使用 Django 查询 PostgreSQL 中的 jsonb 字段:IN 与 CONTAINS

Querying jsonb fields in PostgreSQL using Django: IN vs. CONTAINS

当 Django 的 ORM 将使用 CONTAINS 的 JSONB 查询转换为 SQL 时,它使用了工作正常的 ->> 运算符。

例如:

"metadata__my_field_name__icontains": "1234"

运行s 为:

...WHERE UPPER(("table"."metadata" ->> my_field_name)::text) LIKE UPPER(%1234%)...

效果很好。

但是,当我尝试使用 IN 运算符和值列表时:

"metadata__my_field_name__in": my_list

生成的 SQL 使用 JSON,而不是像这样的 JSONB 运算符:

..."table"."metadata" -> 'my_id') IN ('1234', '3456', ...

虽然它 运行s,但它不是 return 预期值(空集)。相比之下,如果我使用 JSONB 运算符 ->> 手动 运行 相同的查询,则预期值为 returned。另请注意,ID 已转换为字符串。我是 运行宁 Django 2.2。

有没有办法强制 Django 使用 JSONB 运算符?

好的,事实证明使用自定义查找是可行的。像这样:

from django.contrib.postgres.fields.jsonb import (
    KeyTransform, KeyTransformTextLookupMixin
)
from django.db.models.lookups import In

@KeyTransform.register_lookup
class KeyTransformIdIn(KeyTransformTextLookupMixin, In):
    lookup_name = 'id_in'
    prepare_rhs = False

    def as_sql(self, compiler, connection):
        lhs_sql, lhs_params = self.process_lhs(compiler, connection)
        rhs_sql, rhs_params = self.process_rhs(compiler, connection)
        sql = "%s::int IN %s" % (lhs_sql, rhs_sql)
        params = [*lhs_params, *rhs_params]
        return sql, params

来自 KeyTransformTextLookupMixin 来源 code comments:

"""
Mixin for combining with a lookup expecting a text lhs from a JSONField
key lookup. Make use of the ->> operator instead of casting key values to
text and performing the lookup on the resulting representation.
"""

内置 django.db.models.lookups.In class 提供正确的右侧处理,将整数列表转换为正确的 PostgreSQL。

...WHERE ("table"."metadata" ->> 'my_id')::int IN (1234, 3456...