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
相关产品推荐
相关产品推荐

