使用 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...
当 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...