Reputation: 601
Let's say I have the following model structure:
Parent():
Child():
parent = ForeignKey(Parent)
GrandChild():
child = ForeignKey(Child)
state = BooleanField()
num = FloatField()
I'm trying to from the Parent ViewSet
, recover the following:
I can do the following:
queryset = Parent.objects\
.annotate(child_count=Count('child'))\
.annotate(sum_total=Sum('child__grandchild__num'))
This gives me (1) but instead of (2) it gives me the SUM for ALL grandchildren. How can I filter the grandchildren appropriately while ensuring I have all of the Parent
objects still in the QuerySet?
Upvotes: 6
Views: 7107
Reputation: 9931
Try using filter before the annotate
queryset = Parent.objects.filter(child__grandchild__state='True')\
.annotate(child_count=Count('child'))\
.annotate(sum_total=Sum('child__grandchild__num'))
Upvotes: 1
Reputation: 126
You can do the following:
qs = Parents.objects.all()
child_count = Count('children')
num_sum = Sum('children__grandchildren__num', filter=Q(children__grandchildren__state=True))
qs = qs.annotate(child_count=child_count).annotate(num_sum=num_sum)
chidlren and grandchildren are the related names that you can define in your models
Upvotes: 0
Reputation: 935
Which version of django are you using? You can use subquery as well if version is supported.
from django.db.models import OuterRef, Subquery
Parent.objects
.annotate(child_count=Count('child'))
.annotate(
grandchild_count_for_state_true=Subquery(
GrandChild.objects.filter(
state=True,
child=OuterRef('pk')
).values('parent')
.annotate(cnt=Sum('child__grandchild__num'))
.values('cnt'),
num=models.IntegerField()
)
)
You can optimise this through aggregation query.
Upvotes: 5