Is it possible to access annotated values on querysets in templates?
For example I have the following queryset that I'm passing to my template:
context[videos] = Videos.objects.annotate(view_count=Count(views)).order_by(view_count)[:100]
In my template I'm trying to get the view count like this:
{% for video in videos %}
{{ video.view_count }}
{% endfor %}
Which displays nothing.
However if I use:
{{ video.views.count }}
It seems fine - but i believe the second option recalculates the view count. I'd like to use the annotated value since it should already be calculated.
It would make sense that the QuerySet aggregation method per-item, annotate(), has such a name because it annotates (sets) the aggregated value to each item (model instance) it yields, like a normal field, for example:
# Build an annotated queryset
>>> q = Book.objects.annotate(Count('authors'))
# Interrogate the first object in the queryset
>>> q[0]
<Book: The Definitive Guide to Django>
>>> q[0].authors__count
2
# Interrogate the second object in the queryset
>>> q[1]
<Book: Practical Django Projects>
>>> q[1].authors__count
1
About the names:
the name for the annotation is automatically derived from the name of the aggregate function and the name of the field being aggregated. You can override this default name by providing an alias when you specify the annotation:
>>> q = Book.objects.annotate(num_authors=Count('authors'))
>>> q[0].num_authors
2
>>> q[1].num_authors
1
For example with:
context['videos'] = Videos.objects.annotate(view_count=Count('views')).order_by('-view_count')[100:]
You could use:
[video.view_count for video in context['videos']]
Which should be the same as using values_list():
Videos.objects.annotate(view_count=Count('views')).values_list('view_count', flat=True)
And similar to:
{% for video in videos %}
{{ video.view_count }}
{% endfor %}
That said, unlike normal fields, the order in which filters are applied matters, you've been warned B)