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?
In the Django framework, both annotate and aggregate are responsible for identifying a given value set summary. Among these, annotate identifies the summary from each of the items in the queryset. Whereas in the case of aggregate, the summary is calculated for the entire queryset.
Unlike aggregate() , annotate() is not a terminal clause. The output of the annotate() clause is a QuerySet ; this QuerySet can be modified using any other QuerySet operation, including filter() , order_by() , or even additional calls to annotate() .
What is an annotation? Annotate generate an independent summary for each object in a queryset. In simpler terms, annotate allows us to add a pseudo field to our queryset. This field can then further be used for filter lookups or ordering.\
to Django users. According to the documentation on models. OuterRef: It acts like an F expression except that the check to see if it refers to a valid field isn't made until the outer queryset is resolved.
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 0
s and 1
s for the inner Case
statement, resulting in a count of the number of matches.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With