Django PostgreSQL嵌套JSONField查询:匹配任意层级指定值
解决Django Postgres JSONField任意层级嵌套值的查询问题
嘿,这个问题我之前踩过坑!官方文档里的data__values__contains=['Melanie']确实搞不定多层嵌套的JSON结构——它只能遍历JSON顶层的value,没法深入到嵌套的数组或者对象里去搜索。下面给你两个靠谱的解决方案:
方案一:使用Django原生支持的JSON路径查询(推荐)
Postgres的JSON路径语法支持递归查找任意层级的内容,Django已经封装了对这个特性的支持。你可以通过__jsonpath查询条件来实现:
from django.db.models import Value # 直接搜索指定值 Entity.objects.filter(data__jsonpath=Value('$[*]..name == "Melanie"')) # 更灵活的参数化写法(避免硬编码) target_name = "Melanie" Entity.objects.filter(data__jsonpath=Value(f'$[*]..name == "{target_name}"'))
语法解释:
$代表整个JSON数据[*]匹配数组中的所有元素..name递归查找所有层级下的name键== "Melanie"判断该键的值是否等于目标字符串
如果你的搜索不需要限定键名(比如要在整个JSON的任意位置找值),可以把路径改成$[*]..* == "Melanie",这样会匹配任意键下的目标值。
方案二:使用Raw SQL查询
如果对JSON路径语法不太熟悉,直接写Raw SQL也是个稳妥的选择,利用Postgres的jsonb_path_exists函数来判断:
target_value = "Melanie" entities = Entity.objects.raw( """ SELECT * FROM your_app_entity WHERE jsonb_path_exists(data, %s) """, [f'$[*]..name == "{target_value}"'] )
注意把your_app_entity替换成你实际的数据库表名(Django默认是应用名_模型名的小写形式,比如你的app叫myapp,表名就是myapp_entity)。
为什么官方的方法无效?
data__values__contains=['Melanie']的逻辑是提取JSON顶层所有value组成的集合,然后检查目标值是否在这个集合里。但你的data是嵌套的数组+对象结构,顶层value是一个个对象,不是字符串,所以这个方法自然找不到深层的Melanie。
内容的提问来源于stack exchange,提问作者Paul R




