174 lines
5.7 KiB
Python
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"
|