Reputation: 1562
I have the following Model in 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)
So for every A there are many entries in C, and for every B there are also many entries in C. But for every entry in C there is exactly one entry in A and one in B.
I would like to sum up the B.points for a given A, but I have to go over C.
How can I do that in Django? I would know how to do that in SQL if that helps?
Upvotes: 1
Views: 223
Reputation: 476554
You can .annotate(..)
[Django-doc] the A
s, like:
from django.db.models import Sum A.objects.annotate( total_points=Sum('c__b__points') )
If you for example always want to annotate your A
objects, you can define a manager for that:
class WithPointsManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
total_points=Sum('c__b__points')
)
and then define this manager on the A
class, like:
class A(models.Model):
nr = models.IntegerField()
objects = WithPointsManager()
So now if you perform an A.objects.all()
, the A
s will have a total_points
attribute. Note that of course this will have a certain cost at the database side.
Then all A
objects that arise from this QuerySet
, will contain an extra .total_points
attribute that contains the sum of all B
s that are related to a C
that is related to that A
.
Or for a given A
object, you can .aggregate(..)
[Django-doc], like:
from django.db.models import Sum
some_a.c_set.aggregate(
total_points=Sum('b__points')
)['total_points']
This will return the sum of the points
of related B
objects of the set of C
s that are related to some_a
.
Upvotes: 4