I searched a lot on internet but could not find a similar question.
I have 3 models : Domain
, Topic
, Post
Each Domain
can have many Topics
and each Topic
can have many Posts
.
Topic
has a foreign key
to Domain
and Post
has a foreign key
to Topic
.
So I can include count of Posts
in Topic
by annotate(Count('posts'))
and I can include count of Topics
in Board
by annotate(Count('topics'))
Is there any way to include count of Posts
in Board
by annotate
?
Yes, you can use double underscores (__
) to look through a relation:
from django.db.models import Count
Domain.objects.annotate(
num_posts=Count('topics__posts')
)
if you combine this with counting the number of Topic
s, you will need to add distinct=True
to the Count
of the Topic
s, since this will make two JOIN
s, and the JOIN
on Post
s will act as a "multiplier":
from django.db.models import Count
Domain.objects.annotate(
num_posts=Count('topics__posts'),
num_topics=Count('topics', distinct=True)
)
This will result in a query like:
SELECT domain.*
COUNT(post.id) AS num_posts
COUNT(DISTINCT topic.id) AS num_topics
FROM domain
LEFT OUTER JOIN topic ON topic.domain_id = domain.id
LEFT OUTER JOIN post ON post.topic_id = topic.id
GROUP BY domain.id
If you would have omitted the distinct=True
, the same topic would be counted multiple times (exactly the same number of times as the number of posts related to that topic), and thus num_topics
should then be the same as num_posts
. By using DISTINCT
we count the number of unique topics in each group.