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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 06:55:32