Reputation: 13329
I have a model of Photos taken. I am building a heatmap with Javascript of when photos were taken of the last7 days. I am showing it per hour.
My Photo Model has a timestamp DateTime field. How would I make a list like this showing total photos per hour per day for the past week?
The javascript expects an array like this:
const heatmapDataSource = [
[0, 0, 3],
[6, 23, 3],
....
];
heatmapDataSource[0][0] is the day of the week (Today (Tuesday) 0, last week Wednesday (6) - Today is always 0
heatmapDataSource[0][1] is hour (0 == 24:00 and 23 == 23:00 etc)
heatmapDataSource[0][2] is the count value for that hour
Hope this makes sense!
So far I have put this together as a start to get counting:
Photo.objects.annotate(
hour=Trunc('timestamp', 'hour', output_field=DateTimeField())
).values('timestamp__hour', 'timestamp__day').annotate(photos=Count('id'))
Outputs:
<QuerySet [{'timestamp__hour': 10, 'timestamp__day': 10, 'photos': 8}, {'timestamp__hour': 12, 'timestamp__day': 13, 'photos': 1}]>
The Photo Model:
class Photo(models.Model):
camera = models.ForeignKey(Camera, null=True, on_delete=models.PROTECT)
image = models.ImageField()
timestamp = models.DateTimeField(auto_now=True)
UDPATE
This is what I have sofar that is almost there..
import datetime as DT
today = DT.date.today()
week_ago = today - DT.timedelta(days=7)
from django.db.models.functions import ExtractWeekDay
Photo.objects.filter(timestamp__gte=week_ago).annotate(weekday=ExtractWeekDay('timestamp')).annotate(hour=Trunc('timestamp', 'hour', output_field=DateTimeField())).values('timestamp__hour', 'weekday').annotate(photos=Count('id'))
Upvotes: 1
Views: 440
Reputation: 476584
First we need to make some fixes to the query itself: the __day
will have a range of 1-31, which is probably not what we want. We want the week day, so:
from django.db.models import Count
from django.db.models.functions import ExtractHour, ExtractWeekDay
qs = Photo.objects.annotate(
hour=ExtractHour('timestamp'),
day=ExtractWeekDay('timestamp')
).values('hour', 'day').annotate(
photos=Count('id')
).order_by('hour', 'day')
Next we will need to do some post processing:
from datetime import date
dow = date.today().isoweekday() + 1
result = [
[(row['day'] - dow) % 7, row['hour'], row['photos']]
for row in qs
]
This will result in an n×3-list, that can then, for example, be transmitted through JSON.
Upvotes: 1