Django中如何通过OuterRef关联TextField实现_in过滤查询?
解决Django Subquery中OuterRef配合__in过滤的问题
你的核心问题是试图用Python字符串处理函数(str()、split())操作ORM层面的OuterRef表达式,这是行不通的——OuterRef是数据库查询的引用,只能用Django提供的数据库函数在数据库层面处理其值,不能用Python代码直接操作。
正确实现方案
以下是基于PostgreSQL的修复代码(如果使用MySQL,需调整字符串分割逻辑):
from django.db.models import OuterRef, Subquery, Cast, FloatField, Coalesce, Func, Value, F from django.db.models.functions import Split UserAccount.objects.filter(groups__name__contains=group).annotate( spend=Cast( Subquery( FacebookStatistic.objects.filter( # 数据库层面分割逗号字符串为数组,同时匹配去掉前缀的广告账户ID Split(OuterRef('facebook_ad_accounts'), Value(',')).contains( Func( F('ad_account__id_ad'), Value('act_'), function='REPLACE', template="%(function)s(%(expressions)s, %(value)s, '')", value=Value('act_') ) ) ).annotate( spd=Coalesce(Func('spend', function='Sum'), 0, output_field=FloatField()) ).values('spd')[:1] # 限制返回单个值,避免Subquery报错 ), output_field=FloatField() ) )
关键修复点
- 替换Python字符串处理为数据库函数:用
Split函数在数据库层面分割facebook_ad_accounts的逗号字符串为数组,用REPLACE函数移除ad_account__id_ad的act_前缀,再通过contains实现原__in的匹配逻辑。 - 确保Subquery返回单个值:添加
[:1]切片,保证子查询只返回一条汇总结果,符合Subquery的使用要求。
适配MySQL的调整
如果你的项目使用MySQL,由于MySQL原生没有Split函数,需要用JSON_TABLE来分割字符串,示例如下:
# MySQL版本的子查询过滤条件 Func( F('ad_account__id_ad'), function='REPLACE', template="%(function)s(%(expressions)s, 'act_', '')" ).in_( Subquery( UserAccount.objects.filter(id=OuterRef('id')) .annotate( json_str=Func(F('facebook_ad_accounts'), Value(','), function='REPLACE', template='["%(expressions)s"]') ) .annotate( account_id=Func('json_str', function='JSON_TABLE', template="%(function)s(%(expressions)s, '$[*]' COLUMNS(val TEXT PATH '$'))") ) .values('account_id') ) )
内容的提问来源于stack exchange,提问作者Andrii
相关产品推荐
相关产品推荐

