feat: add person stats to dashboard

This commit is contained in:
relikd
2023-06-10 19:33:45 +02:00
parent 231433b65e
commit ccfc0518e3
4 changed files with 106 additions and 23 deletions

View File

@@ -1,8 +1,11 @@
from django.db.models import Q, F, Sum, Count, ExpressionWrapper, IntegerField
from django.db.models.functions import Substr
from django.db.models.lookups import LessThan
from django.views.generic import TemplateView
from app.base.models import Booking, BookingType, Trait, TraitMapping
from app.base.models import (
Booking, BookingType, CourseVisit, Person, Trait, TraitMapping
)
from app.base.views.login import LoginRequired
from app.base.views.model_views.base import ViewOptions
@@ -23,30 +26,20 @@ class DashboardView(DashboardOptions, TemplateView):
book_types = dict(BookingType.objects.values_list('key', 'label'))
trait_types = dict(Trait.objects.values_list('key', 'label'))
# Booking stats
book_by_type = stats_for_booking('type')
book_by_month = {}
for stat in stats_for_booking('month'):
year, month = stat['month'].split('-')
if year not in book_by_month:
book_by_month[year] = [[0, 0] for x in range(13)]
book_by_month[year][0][0] += stat['sum']
book_by_month[year][0][1] += stat['count']
book_by_month[year][int(month)][0] += stat['sum']
book_by_month[year][int(month)][1] += stat['count']
context['booking'] = {
'labels': book_types,
'by_type': book_by_type,
'by_month': book_by_month,
'by_type': stats_for_booking('type'),
}
context['trait'] = {
'labels': trait_types,
'by_type': stats_for_traits(),
}
context['person'] = {
'by_count': stats_for_person_count(),
}
context['by_month'] = stats_by_month()
context['head'] = {
'person': Person._meta.verbose_name_plural,
'bookings': Booking._meta.verbose_name_plural,
'booking_types': BookingType._meta.verbose_name_plural,
'traits': Trait._meta.verbose_name_plural,
@@ -55,9 +48,59 @@ class DashboardView(DashboardOptions, TemplateView):
return context
def stats_for_person_count():
today = date.today()
last_year = today.replace(year=today.year - 1)
stats = Person.objects.aggregate(
total=Count(1),
single_visit=Sum(LessThan(
# TODO: other DBs dont use microseconds
ExpressionWrapper(F('last_visit') - F('created'),
output_field=IntegerField()),
3 * 86_400_000_000)), # 3 days
long_not_seen=Sum(Q(last_visit__lt=last_year)),
)
stats['no_booking'] = stats['total'] - Booking.objects.aggregate(
c=Count('user', distinct=True))['c']
stats['no_course'] = stats['total'] - CourseVisit.objects.aggregate(
c=Count('participant', distinct=True))['c']
return stats
def stats_by_month():
stats = {}
for stat in stats_for_person_by_month():
year, month = stat['month'].split('-')
if year not in stats:
stats[year] = [[0, 0, 0] for x in range(13)]
stats[year][0][2] += stat['count']
stats[year][int(month)][2] += stat['count']
for stat in stats_for_booking('month'):
year, month = stat['month'].split('-')
if year not in stats:
stats[year] = [[0, 0, 0] for x in range(13)]
stats[year][0][0] += stat['sum']
stats[year][0][1] += stat['count']
stats[year][int(month)][0] += stat['sum']
stats[year][int(month)][1] += stat['count']
return sorted(stats.items(), reverse=True)
def stats_for_person_by_month():
return Person.objects.values(
month=Substr('created', 1, 7), # YYYY-MM
).annotate(count=Count(1)).order_by('month')
def stats_for_booking(groupby: str):
_Q = Booking.objects.filter(Q(end_time__isnull=False)).annotate(
# for whatever reason django uses nano seconds
# TODO: other DBs dont use microseconds
diff=ExpressionWrapper(
(F('end_time') - F('begin_time')) / 60_000_000,
output_field=IntegerField()),