Django中如何正确筛选JSONField列表内符合数值条件的记录?
解决Django JSONField中列表类型值的误匹配问题
这个问题其实是PostgreSQL(假设你用的是PostgreSQL,Django的JSONField在该数据库下基于JSONB实现)的JSON类型比较规则导致的:JSONB的类型优先级是 null < 布尔值 < 数值 < 字符串 < 数组 < 对象,所以当你用pages__t__gte=2查询时,任何数组类型的t值都会被判定为“大于等于数值2”,哪怕数组里的元素全是小于2的数,这就导致了误匹配。
根据你的实际需求,有两种解决方案:
方案1:仅筛选t为单个数值且满足条件的记录
如果你只需要t是单个数值且≥指定值的记录,可以先通过__type筛选出数值类型的t,再进行数值比较:
Books.objects.filter( pages__t__type='number', # 确保t是数值类型(非数组/字符串等) pages__t__gte=2 )
__type是Django 3.1及以上版本支持的JSONField查找方式,'number'对应JSON中的数值类型,这样就能直接排除掉所有t为列表的记录。
方案2:筛选t为单个数值≥指定值,或列表中存在元素≥指定值的记录
如果你需要同时包含“单个数值达标”和“列表中有至少一个元素达标”的记录,可以结合Q表达式和原生SQL子查询来实现:
from django.db.models import Q from django.db import connection Books.objects.filter( # 第一种情况:t是单个数值且≥2 Q(pages__t__type='number', pages__t__gte=2) | # 第二种情况:t是列表且存在元素≥2 Q( pages__t__type='array', id__in=Books.objects.raw(""" SELECT DISTINCT b.id FROM books b, jsonb_array_elements(b.pages->'t') elem WHERE elem::numeric >= %s """, [2]) ) )
这里的子查询通过jsonb_array_elements展开列表中的每个元素,筛选出存在元素≥2的记录ID,再和主查询关联,确保只有列表中确实有符合条件元素的记录才会被选中。
内容的提问来源于stack exchange,提问作者N.Bar
相关产品推荐
相关产品推荐

