Reputation: 1108
This is a very stupid thing, I know, but I just don't seem to get the handle on Django aggregate and annotate functions.
I have a very simple set of models: Events
, Areas
and Types
. An event has foreign keys pointing to Area
and Type
. I would simply like to have the number of forthcoming events for any area and the same for any type, i.e. Area1 - 5 forthcoming events, Area2 - 6, or Type1 - 34 events and so on.
I would like to avoid writing custom SQL, and the q operator if possible.
Upvotes: 20
Views: 56260
Reputation: 3395
from django.db.models import Count
class Area(models.Model):
area_name = models.CharField(...)
address = models.CharField(...)
class Event(models.Model):
event_name = models.CharField(...)
area = models.ForeignKey(Area,...)
area_query = Area.objects.filter(yourfilter)
total_event_per_area = Event.objects.filter(area__in=area_query).values('area').annotate(Count('id'))
print(total_event_per_area)
<QuerySet [{'area': 2, 'id__count': 2}, {'area': 4, 'id__count': 3}]>
Upvotes: 0
Reputation: 4287
for a given area:
my_area = Area.objects.all()[0]
Event.objects.filter(area=my_area).count()
annotation
events = Event.objects.annotate(Count('area'))
for event in events:
print event, event.area__count
or
events = Event.objects.annotate(count=Count('area'))
for event in events:
print event, event.count
See the following docs:
https://docs.djangoproject.com/en/dev/ref/models/querysets/#annotate
Upvotes: 23
Reputation: 1108
Thank you all very much. The problem I was having is documented in the last version, it is about the annotate and filter precedence.
areas = Area.objects.filter(event__in = eventQuery).annotate(num=Count('event'))
My error was in the fact that I was doing annotate first and filter second.
Upvotes: 3
Reputation: 599530
If you just need the total number of events for a single area, you don't need either annotate
or aggregate
, a simple count
will do:
Event.objects.filter(area=my_area).count()
If you want the count of events for multiple areas, you need annotate
in conjunction with values
:
Event.objects.values('area').annotate(Count('area'))
Upvotes: 21