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

Django StringAgg搭配条件表达式使用distinct报错的原因与解决方法

问题原因及解决方案

问题原因

PostgreSQL有个硬性规则:当聚合函数用DISTINCT去重时,ORDER BY里的所有表达式必须直接出现在聚合函数的参数列表里。

第一个示例里,StringAgg的参数是"credits__role__name",ordering也指定了同一个字段,完全符合规则,所以能正常运行。

第二个示例就不一样了:StringAgg的参数是Case(When(...))这个条件表达式,但ordering写的是"credits__entity__name"——这个字段只是嵌套在Case里面,并没有直接作为聚合参数存在,PostgreSQL不认它属于聚合参数的一部分,所以直接抛出ProgrammingError。

可行解决方案

方案一:用FilteredRelation先过滤再聚合

先通过FilteredRelation把符合类型要求的credits筛选出来,再对筛选后的关联字段做StringAgg,这样就和第一个示例的常规用法一致,不会触发PostgreSQL的限制:

from django.db.models import FilteredRelation, Q

if request.GET.get("order[0][name]"):
    order = request.GET["order[0][name]"]
    if order == "credits_primary":
        releases = releases.annotate(
            primary_credits=FilteredRelation(
                'credits', condition=Q(credits__type="primary")
            )
        ).annotate(
            credits_primary=StringAgg(
                'primary_credits__entity__name',
                delimiter=", ",
                distinct=True,
                ordering='primary_credits__entity__name'
            )
        )
    elif order == "credits_secondary":
        releases = releases.annotate(
            secondary_credits=FilteredRelation(
                'credits', condition=Q(credits__type="secondary")
            )
        ).annotate(
            credits_secondary=StringAgg(
                'secondary_credits__entity__name',
                delimiter=", ",
                distinct=True,
                ordering='secondary_credits__entity__name'
            )
        )
# 后续排序代码保持不变

方案二:让ordering和聚合参数用同一个Case表达式

把ordering设置成和聚合参数完全一样的Case表达式,确保排序用的表达式属于聚合参数的一部分,同时指定output_field让Django生成正确的SQL:

from django.db.models import Case, When, Value, CharField

if request.GET.get("order[0][name]"):
    order = request.GET["order[0][name]"]
    if order == "credits_primary":
        # 定义可复用的Case表达式
        primary_case = Case(
            When(credits__type="primary", then="credits__entity__name"),
            default=Value(None),
            output_field=CharField()
        )
        releases = releases.annotate(credits_primary=StringAgg(
            primary_case,
            delimiter=", ",
            distinct=True,
            ordering=primary_case
        ))
    elif order == "credits_secondary":
        secondary_case = Case(
            When(credits__type="secondary", then="credits__entity__name"),
            default=Value(None),
            output_field=CharField()
        )
        releases = releases.annotate(credits_secondary=StringAgg(
            secondary_case,
            delimiter=", ",
            distinct=True,
            ordering=secondary_case
        ))
# 后续排序代码保持不变

说明:方案一逻辑更清晰,可读性更高,优先推荐;方案二则不需要额外的关联过滤,直接通过调整表达式满足规则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 04:35:53