khana/khana/people/templatetags/statistics.py

272 lines
9.2 KiB
Python

from django import template
from django.db.models import Count, Min
from django.shortcuts import get_object_or_404
from khana.people.models import Gymnast, CanDoRelation
from khana.objective.models import Educative, Skill
register = template.Library()
def __getInformationsFromLevel(gymnast, totalKnownSkill):
"""
Calcule toutes les statistiques par rapport au niveau.
"""
context = {}
maxLevelEducative = Educative.objects.filter(cando__gymnast=gymnast.id).order_by(
"-level"
)[:1]
# Nombre de Skill que le gymnaste sait faire, groupé par niveau
nbKnownSkillByLevel = (
Skill.objects.values("level")
.filter(cando__gymnast=gymnast.id)
.order_by("level")
.annotate(nbknownskill=Count("id"))
)
if maxLevelEducative:
# Niveau maximum de l'élève
context["maxLevelEducative"] = maxLevelEducative[0].level
# Nombre de Skill qui ont un niveau inférieur ou égal
context["totalSkill"] = Skill.objects.filter(
level__lte=context["maxLevelEducative"]
).count()
# Nombre de Skill qui ont un niveau intérieur ou égal, groupé par niveau
nbSkillByLevel = (
Skill.objects.values("level")
.filter(level__lte=context["maxLevelEducative"])
.order_by("level")
.annotate(nbskill=Count("id"))
)
j = 0
tmp = None
percentages = []
for skill in nbSkillByLevel:
tmp = None
if skill["level"] == nbKnownSkillByLevel[j]["level"]:
if skill["nbskill"] != nbKnownSkillByLevel[j]["nbknownskill"]:
tmp = (
skill["level"],
skill["nbskill"],
nbKnownSkillByLevel[j]["nbknownskill"],
int(
(nbKnownSkillByLevel[j]["nbknownskill"] / skill["nbskill"])
* 100
),
)
j += 1
else:
tmp = (skill["level"], skill["nbskill"], 0, 0)
if tmp:
percentages.append(tmp)
context["percentages"] = percentages
# Liste des Skill que le gymnaste ne sait PAS faire, classé par niveau (ayant un niveau inférieur ou égal au niveau max du gym)
context["skillByLevel"] = Skill.objects.filter(
level__lte=context["maxLevelEducative"]
).exclude(cando__gymnast=gymnast.id)
# Liste des Skill que le gymnaste ne sais PAS faire (ayant un niveau plus grand que le niveau max du gym)
context["newUnknownSkill"] = Skill.objects.filter(
level__gt=context["maxLevelEducative"]
).exclude(cando__gymnast=gymnast.id)
else:
context["maxLevelEducative"] = 0
context["totalSkill"] = Skill.objects.all().count()
context["newUnknownSkill"] = Skill.objects.all()
# Calcul des statistiques
if context["totalSkill"] != 0:
context["completude"] = "%s%%" % (
int((totalKnownSkill / context["totalSkill"]) * 100)
)
context["evaluatedLevel"] = int(
context["maxLevelEducative"] * (totalKnownSkill / context["totalSkill"])
)
else:
context["completude"] = 0
context["evaluatedLevel"] = 0
return context
def __getInformationsFromRank(gymnast, totalKnownSkill):
"""
Calcule toutes les statistiques par rapport au rang.
"""
context = {}
min_rank = (
Skill.objects.values("rank")
.exclude(cando__gymnast=gymnast.id)
.order_by("rank")
.aggregate(Min("rank"))["rank__min"]
)
# print(min_rank)
# Nombre de Skill que le gymnaste sait faire, groupé par niveau
nbKnownSkillByRank = (
Skill.objects.values("rank")
.filter(cando__gymnast=gymnast.id)
.order_by("rank")
.annotate(nbknownskill=Count("id"))
)
# Rang maximum dans les éducatifs que le gymnaste sait faire
maxRankEducative = Educative.objects.filter(cando__gymnast=gymnast.id).order_by(
"-rank"
)[:1]
if maxRankEducative:
# Niveau maximum de l'élève
context["maxRankEducative"] = maxRankEducative[0].rank
# Nombre de Skill qui ont un niveau inférieur ou égal
context["totalSkill"] = Skill.objects.filter(
level__lte=context["maxRankEducative"]
).count()
# Nombre de Skill qui ont un niveau intérieur ou égal, groupé par niveau
nbSkillByRank = (
Skill.objects.values("rank")
.filter(level__lte=context["maxRankEducative"])
.order_by("rank")
.annotate(nbskill=Count("id"))
)
j = 0
tmp = None
percentages = []
for skill in nbSkillByRank:
# les deux lignes ci-derssous doiuvent partir
if j >= nbKnownSkillByRank.count():
break
tmp = None
# print(j)
if skill["rank"] == nbKnownSkillByRank[j]["rank"]:
if skill["nbskill"] != nbKnownSkillByRank[j]["nbknownskill"]:
tmp = (
skill["rank"],
skill["nbskill"],
nbKnownSkillByRank[j]["nbknownskill"],
int(
(nbKnownSkillByRank[j]["nbknownskill"] / skill["nbskill"])
* 100
),
)
j += 1
else:
# print('dans le else')
tmp = (skill["rank"], skill["nbskill"], 0, 0)
if tmp:
percentages.append(tmp)
context["percentages"] = percentages
# Liste des Skill que le gymnaste ne sait PAS faire, classé par niveau (ayant un niveau inférieur ou égal au niveau max du gym)
context["skillByRank"] = Skill.objects.filter(
level__lte=context["maxRankEducative"]
).exclude(cando__gymnast=gymnast.id)
# Liste des Skill que le gymnaste ne sais PAS faire (ayant un niveau plus grand que le niveau max du gym)
context["newUnknownSkill"] = Skill.objects.filter(
level__gt=context["maxRankEducative"]
).exclude(cando__gymnast=gymnast.id)
else:
context["maxRankEducative"] = 0
context["totalSkill"] = Skill.objects.all().count()
context["newUnknownSkill"] = Skill.objects.all()
# Calcul des statistiques
if context["totalSkill"] != 0:
context["completude"] = "%s%%" % (
int((totalKnownSkill / context["totalSkill"]) * 100)
)
context["evaluatedLevel"] = (min_rank - 1) + (
int(context["maxRankEducative"] * (totalKnownSkill / context["totalSkill"]))
)
else:
context["completude"] = 0
context["evaluatedLevel"] = 0
return context
@register.inclusion_tag("gymnast_statistics.html")
def display_stats(gymnast):
"""
Tag affichant les statistiques d'un gymnaste : le nombre de saut qu'il sait faire (total,
par niveau, par rank, …), calcule la complétude, …
.. todo:: Générer UNE fois la liste de skill que le gymnaste ne sait pas faire (1 query)
et les counts puis, dans le template on parcourt plusieurs fois cette même liste mais on
affiche conditionnellement (par age, par rank, ...)
"""
# Nombre de Skill que le gymnaste sait faire
gymnast_known_skills = gymnast.known_skills.count()
context = __getInformationsFromLevel(gymnast, gymnast_known_skills)
context.update(__getInformationsFromRank(gymnast, gymnast_known_skills))
if gymnast.gender:
context["skillByAge"] = Skill.objects.filter(age_girl__lte=gymnast.age).exclude(
cando__gymnast=gymnast.id
)
else:
context["skillByAge"] = Skill.objects.filter(age_boy__lte=gymnast.age).exclude(
cando__gymnast=gymnast.id
)
context["gymnast"] = gymnast
context["totalKnownSkill"] = gymnast_known_skills
return context
@register.inclusion_tag("gymnast_display_level.html")
def display_level(gymnast):
"""
Tag affichant les statistiques d'un gymnaste : le nombre de saut qu'il sait faire (total,
par niveau, par rank, …), calcule la complétude, …
.. todo:: Générer UNE fois la liste de skill que le gymnaste ne sait pas faire (1 query)
et les counts puis, dans le template on parcourt plusieurs fois cette même liste mais on
affiche conditionnellement (par age, par rank, ...)
"""
# Nombre de Skill que le gymnaste sait faire
gymnast_known_skills = gymnast.known_skills.count()
# print(gymnast_known_skills)
# context = __getInformationsFromLevel(gymnast, gymnast_known_skills)
context = __getInformationsFromRank(gymnast, gymnast_known_skills)
# context.update(__getInformationsFromRank(gymnast, gymnast_known_skills))
if gymnast.gender:
context["skillByAge"] = Skill.objects.filter(age_girl__lte=gymnast.age).exclude(
cando__gymnast=gymnast.id
)
else:
context["skillByAge"] = Skill.objects.filter(age_boy__lte=gymnast.age).exclude(
cando__gymnast=gymnast.id
)
context["gymnast"] = gymnast
context["totalKnownSkill"] = gymnast_known_skills
return context