Django中使用F()访问JSONField嵌套字段触发JSONDecodeError的原因
Django JSONField使用
F('bb__p1')报错的原因解析 问题场景
定义的Django模型:
class Helo(models.Model): id = models.IntegerField(primary_key=True) aa = models.JSONField(null=True) bb = models.JSONField(null=True)
示例数据:
| id | aa | bb |
|---|---|---|
| 1 | {"p1":11 "p2": 22} | {"p1": 33, "p2": 44} |
执行以下查询时出现json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)错误:
test = Helo.objects.filter(aa__p1__gte=F('bb__p1')) test.count()
但执行下面的代码却无报错:
test = Helo.objects.filter(aa__p1__gte=F('bb')) test.count()
原因解析
Django的F()表达式核心是直接引用数据库层面的字段名,它不支持解析ORM为JSONField封装的__嵌套键查询语法。
当你写F('bb__p1')时,Django会把bb__p1当作一个完整的数据库字段名去查找,但你的表中不存在该字段,数据库返回无效内容,后续JSON解析环节就会抛出解码错误。
而F('bb')是直接引用bb这个JSONField字段本身,数据库会返回该字段的完整JSON字符串,因此不会触发解码错误(但这个查询逻辑不符合需求,本质是拿aa里的p1值和整个bb的JSON字符串做比较)。
解决思路
要实现JSONField嵌套键之间的比较,需要借助Func类直接调用数据库的JSON处理函数,以PostgreSQL为例,可以用KeyTextTransform提取嵌套值:
from django.db.models import F from django.db.models.functions import KeyTextTransform test = Helo.objects.annotate( bb_p1=KeyTextTransform('p1', 'bb') ).filter(aa__p1__gte=F('bb_p1')) test.count()
通过annotate先提取bb字段里的p1值并命名为bb_p1,再用F()引用这个注解字段,就能实现预期的查询逻辑。
内容的提问来源于stack exchange,提问作者lyi61pd
相关产品推荐
相关产品推荐

