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

Django子查询过滤时OuterRef是否支持JSONField列表?

问题分析与解决

核心结论:不是OuterRef不支持JSONField,而是Django默认生成的__in查询SQL和MySQL对JSON数组的处理语法不兼容。

报错原因

当你使用id__in=OuterRef('bar_list')时,Django生成的SQL会尝试直接将JSON字段作为IN的参数,类似:

SELECT ... FROM bar WHERE bar.id IN (foo.bar_list)

但MySQL中JSON数组无法直接用于IN语句的参数,必须先将其解析为可识别的行集合或用JSON函数判断关联关系。而你替换为具体列表时,Django会生成IN (1,2,3)这种符合MySQL语法的语句,所以能正常运行。

解决方法

根据MySQL版本,有两种可行方案:

方案1:MySQL 8.0+(支持JSON_TABLE)

利用JSON_TABLE将JSON数组解析为行集,再进行IN关联:

from django.db.models import Func, OuterRef, Subquery

class JSONTable(Func):
    function = 'JSON_TABLE'
    template = "%(function)s(%(expressions)s, '$[*]' COLUMNS(id INT PATH '$'))"

bar_query = Bar.objects.filter(
    id__in=JSONTable(OuterRef('bar_list'))
).values('id')[:1]

foos_with_bar_id = Foo.objects.all().annotate(task_id=Subquery(bar_query))

方案2:兼容MySQL 5.7+(用JSON_CONTAINS判断)

如果你的MySQL版本不支持JSON_TABLE,可以用JSON_CONTAINS判断Bar的id是否存在于Foo的bar_list数组中:

from django.db.models import Func, F, OuterRef, Subquery

class JSONContains(Func):
    function = 'JSON_CONTAINS'
    arity = 2

bar_query = Bar.objects.filter(
    JSONContains(OuterRef('bar_list'), Func(F('id'), function='CAST', template="CAST(%(expressions)s AS JSON)"))
).values('id')[:1]

foos_with_bar_id = Foo.objects.all().annotate(task_id=Subquery(bar_query))

这里通过CAST将Bar的id转为JSON类型,再用JSON_CONTAINS判断是否在目标JSON数组中。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 11:11:11