You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Django将JSONField查询的__unaccent识别为PostgreSQL函数?

问题:Django JSONField中使用unaccent函数实现无重音模糊搜索

场景与问题

我有一个包含JSONField的模型:

class MyModel(models.Model):
    locale_names = models.JSONField()

该JSONField的结构为键是语言代码(如en、fr),值是对应翻译后的字符串。

我需要对JSON中指定语言的翻译值执行无重音的不区分大小写模糊搜索,尝试了以下查询:

MyModel.objects.filter(locale_names__en__unaccent__icontains="Test")

但未得到预期结果——因为Django将__unaccent解析为JSON路径的一部分,而非PostgreSQL的unaccent函数:

预期生成的SQL

-- 预期SQL查询:类似如下
SELECT "app_model"."*" ...
FROM "app_model"
WHERE UPPER(UNACCENT("app_model"."locale_names" ->>'en')::text) LIKE UPPER(UNACCENT('%Test%'))
LIMIT 21

实际生成的SQL

-- 实际生成的SQL查询
SELECT "app_model"."*" ...
FROM "app_model"
WHERE UPPER(("app_model"."locale_names" #>> ARRAY['en','unaccent'])::text) LIKE UPPER('%Test%')
LIMIT 21

补充信息:使用Django 3.2版本,普通CharField上执行__unaccent__icontains查询可正常工作。

解决方案

由于Django 3.2中JSONField的查找逻辑会优先解析__分隔的路径,需要先将JSON中的目标值提取为虚拟字段,再对该字段应用unaccent函数。

方案1:通过annotate提取字段后过滤

先通过annotate将JSON中指定语言的值提取为虚拟字段,再对该字段使用__unaccent__icontains:

from django.db.models import F, Func, Value
from django.contrib.postgres.search import Unaccent

# 提取locale_names中的en字段值为虚拟字段en_name
queryset = MyModel.objects.annotate(
    en_name=Func(F('locale_names'), Value('en'), function='jsonb_extract_path_text')
).filter(
    en_name__unaccent__icontains="Test"
)

此方法会生成符合预期的SQL,unaccent会被正确识别为PostgreSQL函数。

方案2:直接用Func构建查询条件

如果不想使用annotate,可以直接通过Func嵌套调用,将unaccent应用在JSON提取的值上:

from django.db.models import Func, F, Value
from django.contrib.postgres.search import Unaccent

queryset = MyModel.objects.filter(
    # 先提取JSON的en值,再应用unaccent函数
    Func(
        Func(F('locale_names'), Value('en'), function='jsonb_extract_path_text'),
        function='unaccent'
    )__icontains=Unaccent('Test')
)

原理说明

通过annotate或直接嵌套Func,我们先将JSON中的目标值转换为普通的文本表达式,之后Django处理__unaccent__icontains时,就会将其解析为PostgreSQL的unaccent函数调用,而非JSON路径的一部分。

内容的提问来源于stack exchange,提问作者foucdeg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 22:27:17