Files
django-maraudes/statistiques/views.py

174 lines
5.7 KiB
Python

from collections import OrderedDict
from django.core.exceptions import ImproperlyConfigured
from django.shortcuts import redirect
from django.views import generic
from django.db.models import (CharField, NullBooleanField)
from maraudes.notes import Observation
from maraudes.models import Maraude, HORAIRES_APRESMIDI, HORAIRES_SOIREE
from notes.models import Sujet
from .models import FicheStatistique
from .forms import StatistiquesForm, SelectRangeForm
from . import charts
###
NO_DATA = "Aucune donnée"
class FilterMixin(generic.edit.FormView):
form_class = SelectRangeForm
request = None
year = None
def get_initial(self):
return {
'period': self.year,
}
def parse_args(self, request):
period = request.GET.get("period", "0")
self.year = int(period)
def get(self, request, *args, **kwargs):
self.parse_args(request)
return super().get(self, *args, **kwargs)
def _filters(self, prefix):
return {'%s__%s' % (prefix, attr): getattr(self, attr) for attr in ('year',)
if getattr(self, attr) > 0}
def get_observations_queryset(self):
return Observation.objects.filter(**self._filters('created_date'))
def get_maraudes_queryset(self):
return Maraude.objects.filter(**self._filters('date'))
def get_fichestatistiques_queryset(self):
return FicheStatistique.objects.filter(pk__in=self.get_sujets_queryset().values_list('pk'))
def get_sujets_queryset(self, selection=None):
if not selection:
selection = self.get_observations_queryset()
return Sujet.objects.filter(pk__in=selection.values_list('sujet'))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['year'] = self.year
return context
class MultipleChartsView(FilterMixin, generic.TemplateView):
title = None
description = None
_charts = {} # Set of charts managed by the view
_active = None # Name of the active chart
_chart = None # Active chart object
template_name = "statistiques/multiple_charts.html"
def __init__(self, **kwargs):
if not self._charts:
raise ImproperlyConfigured()
super().__init__(**kwargs)
def get(self, request, *args, **kwargs):
self._active = request.GET.get('graph', None)
if self._active:
self._chart = self._charts.get(self._active, None)
return super().get(request, *args, **kwargs)
def get_queryset(self):
""" Returns the queryset of objects used to draw graphs """
raise NotImplementedError("Subclass must implement this method")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = str(self.title)
context['chart_list'] = list(self._charts.keys())
context['active'] = self._active
if self._chart: # Need to instantiate the chart
queryset = self.get_queryset()
context['queryset_count'] = queryset.count()
context['chart'] = self._chart(queryset)
return context
class DashboardView(FilterMixin, generic.TemplateView):
template_name = "statistiques/index.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
maraudes = self.get_maraudes_queryset()
rencontres = self.get_observations_queryset()
context['chart'] = charts.DonneeGeneraleChart(
maraudes=(maraudes,
maraudes.filter(heure_debut=HORAIRES_APRESMIDI),
maraudes.filter(heure_debut=HORAIRES_SOIREE)
),
rencontres=(rencontres,
rencontres.filter(rencontre__maraude__heure_debut=HORAIRES_APRESMIDI),
rencontres.filter(rencontre__maraude__heure_debut=HORAIRES_SOIREE)),
)
return context
class TypologieChartsView(MultipleChartsView):
title = "Typologie"
_charts = OrderedDict(
[('Âge', charts.AgePieChart),
('Genre', charts.GenrePieChart),
] +
[(f.verbose_name, charts.generate_piechart_for_field(f)) for f in FicheStatistique._meta.get_fields()
if f.__class__ in (NullBooleanField, CharField)
]
)
def get_queryset(self):
return self.get_fichestatistiques_queryset()
class FrequentationChartsView(MultipleChartsView):
title = "Fréquentation"
_charts = OrderedDict([
('Par mois', charts.RencontreParMoisChart),
('Par heure', charts.RencontreParHeureChart),
('Par sujet', charts.RencontreParSujetChart),
('Par lieu', charts.RencontreParLieuChart)
])
def get_queryset(self):
return self.get_observations_queryset()
# AjaxMixin
class AjaxOrRedirectMixin(object):
""" For view that should be retrieved by Ajax only. If not,
redirects to the primary view where these are displayed """
def get(self, *args, **kwargs):
""" Redirect to complete details view if request is not ajax """
if not self.request.is_ajax():
return redirect("notes:details-sujet", pk=self.get_object().pk)
return super().get(*args, **kwargs)
class StatistiquesDetailsView(AjaxOrRedirectMixin, generic.DetailView):
model = FicheStatistique
template_name = "statistiques/fiche_stats_details.html"
class StatistiquesUpdateView(AjaxOrRedirectMixin, generic.UpdateView):
model = FicheStatistique
form_class = StatistiquesForm
template_name = "statistiques/fiche_stats_update.html"