导致笛卡尔积的 Django 注释

Posted

技术标签:

【中文标题】导致笛卡尔积的 Django 注释【英文标题】:Django annotation resulting in cartesian product 【发布时间】:2020-04-29 04:10:34 【问题描述】:

我有一个模型,其中一个特定的类将有多个子类。样本设计:

class ParentModel(models.Model):
   ParentName = CharField(max_length=50)

class ChildModelA(models.Model):
   FK1 = ForeignKey(ParentModel, on_delete=models.CASCADE)
   ChildAValue = IntegerField(default=0)

class ChildModelB(models.Model):
   FK2 = ForeignKey(ParentModel, on_delete=models.CASCADE)
   ChildBValue = IntegerField(default=0) 

我要做的是根据“ParentName”总结所有 ChildAValue 和 ChildBValue 的总和。我遇到的问题是,当我在同一个查询中执行这两项操作时,我得到了 ChildA 和 ChildB 之间的笛卡尔积。示例查询:

ParentModel.objects.all().values('ParentName').annotate(
   ChildASum = Sum('childamodel__ChildAValue),
   ChildBSum = Sum('childbmodel__ChildBValue),
)

结果查询集给了我 ChildBValue 的总和乘以 FK 中 ChildA 对象的总数...这意味着指向该特定 Parent 的 6 个 ChildA 对象将我的 ChildB 值乘以 6。反之亦然儿童总和。

有没有什么方法可以在没有多重连接的情况下聚合同一个父级的多个子模型?

谢谢!

【问题讨论】:

【参考方案1】:

是的,您可能需要在此处使用子查询:

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

ParentModel.objects.values('ParentName').annotate(
    ChildASum=Subquery(
        ChildModelA.objects.filter(
           FK1=OuterRef('pk')
        ).annotate(
            total=Sum('ChildAValue')
        ).values('total').order_by('FK1')
   ),
   ChildBSum=Subquery(
        ChildModelB.objects.filter(
           FK2=OuterRef('pk')
        ).annotate(
            total=Sum('ChildAValue')
        ).values('total').order_by('FK1')
   )
)

【讨论】:

以上是关于导致笛卡尔积的 Django 注释的主要内容,如果未能解决你的问题,请参考以下文章

生成笛卡尔积的两个表之间的连接

基于笛卡尔坐标点积的算法计算地理距离

javascript 用于从2D矩阵创建笛卡尔积的递归函数

Erlang List对笛卡尔积的理解

python中带有元组列表的字符串列表的条件笛卡尔积的单线

笛卡尔积请具体解释一下.