首页 > 解决方案 > Django中的聚合

问题描述

我在 Django 中有以下模型:

class A(models.Model):
    nr = models.IntegerField()

class B(models.Model):
    points = models.IntegerField()

class C(models.Model):
    a = models.ForeignKey(A, on_delete=models.CASCADE)
    b = models.ForeignKey(B, on_delete=models.CASCADE)

因此,对于每个 A,C 中都有很多条目,对于每个 B,C 中也有很多条目。但是对于 C 中的每个条目,A 中只有一个条目,B 中只有一个条目。

我想总结给定 A 的 B.points,但我必须超过 C。

我怎么能在 Django 中做到这一点?如果有帮助,我会知道如何在 SQL 中做到这一点?

标签: django

解决方案


您可以.annotate(..)[Django-doc]A s,例如:

从 django.db.models 导入 Sum

A.objects.annotate(
    total_points=Sum('c__b__points') 
)

例如,如果您总是想注释您的A对象,您可以为此定义一个管理器:

class WithPointsManager(models.Manager):

    def get_queryset(self):
        return super().get_queryset().annotate(
            total_points=Sum('c__b__points')
        )

然后在A类上定义这个管理器,比如:

class A(models.Model):
    nr = models.IntegerField()

    objects = WithPointsManager()

所以现在如果你执行 a A.objects.all()As 将有一个total_points属性。请注意,这当然会在数据库端产生一定的成本。

A然后由此产生的所有对象QuerySet都将包含一个额外的.total_points属性,该属性包含与 a 相关的所有Bs 的总和,该 aC与该相关A

或者对于给定的A对象,您可以.aggregate(..)[Django-doc],例如:

from django.db.models import Sum

some_a.c_set.aggregate(
    total_points=Sum('b__points')
)['total_points']

这将返回与 相关的s集合points中相关B对象的总和。Csome_a


推荐阅读