début de réorganisation de la partie statistique
This commit is contained in:
@@ -5,20 +5,24 @@ from . import managers
|
|||||||
|
|
||||||
# Extends 'notes' module
|
# Extends 'notes' module
|
||||||
|
|
||||||
|
|
||||||
class Observation(Note):
|
class Observation(Note):
|
||||||
""" Note dans le cadre d'une rencontre """
|
""" Note dans le cadre d'une rencontre """
|
||||||
|
|
||||||
objects = managers.ObservationManager()
|
objects = managers.ObservationManager()
|
||||||
rencontre = models.ForeignKey('maraudes.Rencontre',
|
rencontre = models.ForeignKey('maraudes.Rencontre',
|
||||||
models.CASCADE,
|
models.CASCADE,
|
||||||
related_name="observations"
|
related_name="observations")
|
||||||
)
|
|
||||||
|
|
||||||
# Note attributes proxies
|
# Note attributes proxies
|
||||||
def note_author(self): return self.rencontre.maraude.referent
|
def note_author(self): return self.rencontre.maraude.referent
|
||||||
|
|
||||||
def note_date(self): return self.rencontre.date
|
def note_date(self): return self.rencontre.date
|
||||||
|
|
||||||
def note_time(self): return self.rencontre.heure_debut
|
def note_time(self): return self.rencontre.heure_debut
|
||||||
|
|
||||||
def note_labels(self): return [self.rencontre.lieu, self.rencontre.heure_debut]
|
def note_labels(self): return [self.rencontre.lieu, self.rencontre.heure_debut]
|
||||||
|
|
||||||
def note_bg_colors(self): return ("info", "info")
|
def note_bg_colors(self): return ("info", "info")
|
||||||
|
|
||||||
class Appel(Note):
|
class Appel(Note):
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import datetime
|
|||||||
import calendar
|
import calendar
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.shortcuts import redirect, reverse
|
from django.shortcuts import redirect, reverse
|
||||||
from django.views import generic
|
from django.views import generic
|
||||||
@@ -26,6 +24,8 @@ from .forms import ( RencontreForm,
|
|||||||
SendMailForm)
|
SendMailForm)
|
||||||
from notes.mixins import NoteFormMixin
|
from notes.mixins import NoteFormMixin
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def derniers_sujets_rencontres():
|
def derniers_sujets_rencontres():
|
||||||
""" Renvoie le 'set' des sujets rencontrés dans les deux dernières maraudes """
|
""" Renvoie le 'set' des sujets rencontrés dans les deux dernières maraudes """
|
||||||
|
|||||||
@@ -19,5 +19,9 @@
|
|||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
{{ par_heure.as_html }}
|
{{ rencontres_par_heure.as_html }}
|
||||||
|
{{ rencontres_par_mois.as_html }}
|
||||||
|
<hr />
|
||||||
|
{{ rencontres_par_sujet.as_html }}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@
|
|||||||
// Wait for the chart to finish drawing before calling the getImageURI() method.
|
// Wait for the chart to finish drawing before calling the getImageURI() method.
|
||||||
google.visualization.events.addListener(chart, 'ready', function () {
|
google.visualization.events.addListener(chart, 'ready', function () {
|
||||||
$("#image-{{ chart.get_html_id }}").attr("href", chart.getImageURI());
|
$("#image-{{ chart.get_html_id }}").attr("href", chart.getImageURI());
|
||||||
$("#wrapper-{{ chart.get_html_id}}").hide();
|
|
||||||
});
|
});
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -15,46 +15,26 @@
|
|||||||
|
|
||||||
{% block breadcrumbs %}
|
{% block breadcrumbs %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<li>Tests</li>
|
<li>Données générales</li>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block page_content %}
|
{% block page_content %}
|
||||||
|
|
||||||
<div class="alert alert-info alert-dismissible">
|
|
||||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
<div class="col-lg-8 text-right">
|
||||||
|
<h3 class="page-header">Données générales</h3>
|
||||||
|
<table class="table table-bordered">
|
||||||
|
<tr><th>...</th><th>Maraudes</th><th>Nombre de rencontres <span class="badge">moyenne par maraude</span></th><th>Personnes</th></tr>
|
||||||
|
<tr><th>Total</th><td>{{nbr_maraudes}}</td><td>{{nbr_rencontres}} <span class="badge">{{nbr_rencontres_moyenne }}</span></td><td>{{nbr_sujets}}</td></tr>
|
||||||
|
<tr><th>Soirée</th><td>{{nbr_maraudes_nuit}}</td><td>{{nbr_rencontres_nuit}} <span class="badge">{{nbr_rencontres_nuit_moyenne }}</span></td><td>{{nbr_sujets_nuit}}</td></tr>
|
||||||
|
<tr><th>Journée</th><td>{{nbr_maraudes_jour}}</td><td>{{nbr_rencontres_jour}} <span class="badge">{{nbr_rencontres_jour_moyenne }}</span></td><td>{{nbr_sujets_jour}}</td></tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="col-lg-4">
|
||||||
|
<div class="alert alert-info">
|
||||||
<p>Voici les données permettant une analyse statistiques des maraudes.</p>
|
<p>Voici les données permettant une analyse statistiques des maraudes.</p>
|
||||||
<p>Vous pouvez sélectionner une période particulière ou l'ensemble des données</p>
|
<p>Vous pouvez sélectionner une période particulière ou l'ensemble des données</p>
|
||||||
<p>Les données sont réparties en trois catégories, accessibles par le menu sur la gauche</p>
|
<p>Les données sont réparties en trois catégories, accessibles par le menu sur la gauche</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-4">
|
|
||||||
<h3 class="page-header">Données générales</h3>
|
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-item list-group-item-danger">
|
|
||||||
<span class="badge">{{ nbr_maraudes }}</span>
|
|
||||||
Nombre de maraudes
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<span class="badge">{{ nbr_maraudes_jour }}</span>
|
|
||||||
dont, Maraudes de journée
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item list-group-item-danger">
|
|
||||||
<span class="badge">{{ nbr_rencontres }}</span>
|
|
||||||
Nombre total de rencontres
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<span class="badge">{{ moy_rencontres }}</span>
|
|
||||||
soit, en <strong>moyenne</strong> par maraude
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item list-group-item-danger">
|
|
||||||
<span class="badge">{{ nbr_sujets_rencontres }}</span>
|
|
||||||
Nombre de sujets rencontrés
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
{% if rencontres_par_mois %}
|
|
||||||
<div class="col-lg-8">
|
|
||||||
<h3 class="page-header">Rencontres par mois</h3>
|
|
||||||
{{ rencontres_par_mois.as_html }}
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
{% block sidebar %}
|
{% block sidebar %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
<hr />
|
|
||||||
<div class="panel panel-primary">
|
<div class="panel panel-primary">
|
||||||
<div class="panel-body text-right">
|
<div class="panel-body text-right">
|
||||||
{% include "statistiques/filter_form.html" %}
|
{% include "statistiques/filter_form.html" %}
|
||||||
@@ -30,10 +29,6 @@
|
|||||||
$("#tab-" + id).attr("class", "active");
|
$("#tab-" + id).attr("class", "active");
|
||||||
$("#wrapper-" + id).show();
|
$("#wrapper-" + id).show();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*$( function() {
|
|
||||||
hideAll();
|
|
||||||
});*/
|
|
||||||
</script>
|
</script>
|
||||||
<ul class="nav nav-tabs">
|
<ul class="nav nav-tabs">
|
||||||
{% for title, graph in graphs %}<li role="presentation" id="tab-{{graph.get_html_id}}"><a href="#" onclick="showGraph('{{graph.get_html_id}}');">{{ title }}</a></li>{% endfor %}
|
{% for title, graph in graphs %}<li role="presentation" id="tab-{{graph.get_html_id}}"><a href="#" onclick="showGraph('{{graph.get_html_id}}');">{{ title }}</a></li>{% endfor %}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ from .forms import StatistiquesForm, SelectRangeForm
|
|||||||
from .charts import PieWrapper, ColumnWrapper
|
from .charts import PieWrapper, ColumnWrapper
|
||||||
|
|
||||||
from maraudes.notes import Observation
|
from maraudes.notes import Observation
|
||||||
from maraudes.models import Maraude
|
from maraudes.models import Maraude, HORAIRES_APRESMIDI, HORAIRES_SOIREE
|
||||||
from notes.models import Sujet
|
from notes.models import Sujet
|
||||||
|
|
||||||
###
|
###
|
||||||
@@ -62,8 +62,10 @@ class FilterMixin(generic.edit.FormMixin):
|
|||||||
def get_fichestatistiques_queryset(self):
|
def get_fichestatistiques_queryset(self):
|
||||||
return FicheStatistique.objects.filter(pk__in=self.get_observations_queryset().values_list('sujet'))
|
return FicheStatistique.objects.filter(pk__in=self.get_observations_queryset().values_list('sujet'))
|
||||||
|
|
||||||
def get_sujets_queryset(self):
|
def get_sujets_queryset(self, selection=None):
|
||||||
return Sujet.objects.filter(pk__in=self.get_observations_queryset().values_list('sujet'))
|
if not selection:
|
||||||
|
selection = self.get_observations_queryset()
|
||||||
|
return Sujet.objects.filter(pk__in=selection.values_list('sujet'))
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
@@ -85,50 +87,36 @@ class DashboardView(FilterMixin, generic.TemplateView):
|
|||||||
|
|
||||||
context['nbr_maraudes'] = maraudes.count() or NO_DATA
|
context['nbr_maraudes'] = maraudes.count() or NO_DATA
|
||||||
context['nbr_maraudes_jour'] = maraudes.filter(
|
context['nbr_maraudes_jour'] = maraudes.filter(
|
||||||
heure_debut=datetime.time(16,00)
|
heure_debut=HORAIRES_APRESMIDI
|
||||||
).count() or NO_DATA
|
).count() or NO_DATA
|
||||||
|
context['nbr_maraudes_nuit'] = maraudes.filter(
|
||||||
|
heure_debut=HORAIRES_SOIREE
|
||||||
|
).count() or NO_DATA
|
||||||
|
|
||||||
context['nbr_rencontres'] = rencontres.count() or NO_DATA
|
context['nbr_rencontres'] = rencontres.count() or NO_DATA
|
||||||
|
rencontres_jour = rencontres.filter(
|
||||||
|
rencontre__maraude__heure_debut=HORAIRES_APRESMIDI
|
||||||
|
)
|
||||||
|
rencontres_nuit = rencontres.filter(
|
||||||
|
rencontre__maraude__heure_debut=HORAIRES_SOIREE
|
||||||
|
)
|
||||||
|
context['nbr_rencontres_jour'] = rencontres_jour.count() or NO_DATA
|
||||||
|
context['nbr_rencontres_nuit'] = rencontres_nuit.count() or NO_DATA
|
||||||
|
|
||||||
|
for r, m in [
|
||||||
|
('nbr_rencontres', 'nbr_maraudes'),
|
||||||
|
('nbr_rencontres_nuit', 'nbr_maraudes_nuit'),
|
||||||
|
('nbr_rencontres_jour', 'nbr_maraudes_jour'),
|
||||||
|
]:
|
||||||
try:
|
try:
|
||||||
context['moy_rencontres'] = int(context['nbr_rencontres'] / context['nbr_maraudes'])
|
context['%s_moyenne' % r] = int(context[r] / context[m])
|
||||||
except (ZeroDivisionError, TypeError):
|
except (ZeroDivisionError, TypeError):
|
||||||
context['moy_rencontres'] = NO_DATA
|
context['%s_moyenne' % r] = NO_DATA
|
||||||
|
|
||||||
if self.year and not self.month: #Show rencontres_par_mois graph
|
context['nbr_sujets'] = self.get_sujets_queryset(selection=rencontres).count()
|
||||||
par_mois = rencontres.order_by().annotate(
|
context['nbr_sujets_jour'] = self.get_sujets_queryset(selection=rencontres_jour).count()
|
||||||
mois=ExtractMonth('created_date')
|
context['nbr_sujets_nuit'] = self.get_sujets_queryset(selection=rencontres_nuit).count()
|
||||||
).values(
|
|
||||||
'mois'
|
|
||||||
).annotate(
|
|
||||||
nbr=Count('pk')
|
|
||||||
)
|
|
||||||
context['rencontres_par_mois'] = ColumnWrapper(
|
|
||||||
SimpleDataSource(
|
|
||||||
[("Mois", "Rencontres")] +
|
|
||||||
[(nom_mois[item['mois']], item['nbr']) for item in par_mois]
|
|
||||||
),
|
|
||||||
options = {
|
|
||||||
"title": "Nombre de rencontres par mois"
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Graph: Fréquence de rencontres par sujet
|
|
||||||
|
|
||||||
nbr_rencontres = rencontres.values('sujet').annotate(nbr=Count('pk')).order_by()
|
|
||||||
context['nbr_sujets_rencontres'] = nbr_rencontres.count()
|
|
||||||
|
|
||||||
|
|
||||||
categories = (
|
|
||||||
('Rencontre unique', (1,)),
|
|
||||||
('Entre 2 et 5 rencontres', range(2,6)),
|
|
||||||
('Entre 6 et 20 rencontres', range(6,20)),
|
|
||||||
('Plus de 20 rencontres', range(20,999)),
|
|
||||||
)
|
|
||||||
get_count_for_range = lambda rg: nbr_rencontres.filter(nbr__in=rg).count()
|
|
||||||
context['graph_rencontres'] = PieWrapper(
|
|
||||||
data= [('Type de rencontre', 'Nombre de sujets')] +
|
|
||||||
[(label, get_count_for_range(rg)) for label, rg in categories],
|
|
||||||
title= 'Fréquence de rencontres'
|
|
||||||
)
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
@@ -245,7 +233,7 @@ class FrequentationStatsView(FilterMixin, generic.TemplateView):
|
|||||||
par_heure = self.calculer_frequentation_par_quart_heure(observations, continu=False)
|
par_heure = self.calculer_frequentation_par_quart_heure(observations, continu=False)
|
||||||
en_continu = self.calculer_frequentation_par_quart_heure(observations, continu=True)
|
en_continu = self.calculer_frequentation_par_quart_heure(observations, continu=True)
|
||||||
|
|
||||||
context['par_heure'] = gchart.AreaChart(
|
context['rencontres_par_heure'] = gchart.AreaChart(
|
||||||
SimpleDataSource(
|
SimpleDataSource(
|
||||||
[("Heure", "Rencontres démarrées", "Au total (démarré + en cours)")] +
|
[("Heure", "Rencontres démarrées", "Au total (démarré + en cours)")] +
|
||||||
[(heure, par_heure[heure], en_continu[heure]) for heure in sorted(par_heure.keys())]
|
[(heure, par_heure[heure], en_continu[heure]) for heure in sorted(par_heure.keys())]
|
||||||
@@ -254,6 +242,41 @@ class FrequentationStatsView(FilterMixin, generic.TemplateView):
|
|||||||
"title": "Fréquentation de la maraude en fonction de l'heure (par quart d'heure)"
|
"title": "Fréquentation de la maraude en fonction de l'heure (par quart d'heure)"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
par_mois = observations.order_by().annotate(
|
||||||
|
mois=ExtractMonth('created_date')
|
||||||
|
).values(
|
||||||
|
'mois'
|
||||||
|
).annotate(
|
||||||
|
nbr=Count('pk')
|
||||||
|
)
|
||||||
|
context['rencontres_par_mois'] = ColumnWrapper(
|
||||||
|
SimpleDataSource(
|
||||||
|
[("Mois", "Rencontres")] +
|
||||||
|
[(nom_mois[item['mois']], item['nbr']) for item in par_mois]
|
||||||
|
),
|
||||||
|
options = {
|
||||||
|
"title": "Nombre de rencontres par mois"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Graph: Fréquence de rencontres par sujet
|
||||||
|
nbr_rencontres = observations.values('sujet').annotate(nbr=Count('pk')).order_by()
|
||||||
|
context['rencontres_par_sujet'] = nbr_rencontres.count()
|
||||||
|
|
||||||
|
categories = (
|
||||||
|
('Rencontre unique', (1,)),
|
||||||
|
('Entre 2 et 5 rencontres', range(2,6)),
|
||||||
|
('Entre 6 et 20 rencontres', range(6,20)),
|
||||||
|
('Plus de 20 rencontres', range(20,999)),
|
||||||
|
)
|
||||||
|
get_count_for_range = lambda rg: nbr_rencontres.filter(nbr__in=rg).count()
|
||||||
|
context['rencontres_par_sujet'] = PieWrapper(
|
||||||
|
data= [('Type de rencontre', 'Nombre de sujets')] +
|
||||||
|
[(label, get_count_for_range(rg)) for label, rg in categories],
|
||||||
|
title= 'Fréquence de rencontres'
|
||||||
|
)
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user