J__
J__

Reputation: 635

Annotate a queryset by a values queryset

I want to annotate a count of objects to a queryset, which I know how to do, but I want the objects counted to have their own filtering.

This works well;

first_model_qs = FirstModel.objects.filter(do a bunch of filtering)
grouped_values_qs = first_model_qs.values('second_model').annotate(Count('pk'))

So I now have a nice queryset with all the first_model counts grouped by second_model ids. Awesome.

What I'd like to do now is something like;

secound_model_qs = SecondModel.objects.annotate(first_model_count = grouped_values_qs)

And then be able to say secound_model_qs.first().first_model_count

Is this possible?

Upvotes: 1

Views: 5597

Answers (1)

Todor
Todor

Reputation: 16020

I think you can do it with a Subquery and more specifically by Using aggregates within a Subquery expression

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

first_model_query = (FirstModel.objects
    # Do the filtering
    .filter(second_model=OuterRef('pk'))
    # add grouping
    .values('second_model')
    # do the aggregation
    .annotate(cnt=Count('pk'))
    # now return only a single column
    .values('cnt')
)

secound_model_qs = SecondModel.objects.annotate(
    first_model_count=Subquery(first_model_query)
) 

Upvotes: 3

Related Questions