Search code examples
pythondjangodjango-modelsdjango-filterdjango-annotate

django annotate - conditional count


I have a model called 'StoreItem' and a model named 'QuoteItem'. A QuoteItem points on a StoreItem.

I'm trying to annotate a counter of how many quote items point on store items, but with conditions to apply on the quote items.

I tried something like this:

items = items.annotate(
            quote_count=Count(
                Case(
                    When(quoteitem__lookup_date__in=this_week, then=1), 
                    output_field=IntegerField()
                )
            )
        )

'items' are a queryset of StoreItems. 'this_week' is a list of dates representing this week (that's the filter I try to apply). After I make the dates thing work I want to add more filters to this conditional count but lets start with that.

Anyway what I'm getting is more like a boolean - if Quote Items that match the condition exists, no matter how many I have, the counter will be 1. else, will be 0.

It looks like the Count(Case()) only check if any item exist and if so return 1, while I want it to iterate over all quote items that point on the store item and count them, if they match the condition (individually).

How do I make it happen?


Solution

  • You need to wrap everything in a Sum statement instead of Count (I find it a bit odd that Count works at all):

    from django.db.models import Case, IntegerField, Sum, When
    
    items = items.annotate(
            quote_count=Sum(
                Case(
                    When(quoteitem__lookup_date__in=this_week, then=1), 
                    output_field=IntegerField()
                )
            )
        )
    

    This basically adds up all the 0s and 1s for the inner Case statement, resulting in a count of the number of matches.