ScoDoc/app/models/evaluations.py

148 lines
4.9 KiB
Python

# -*- coding: UTF-8 -*
"""ScoDoc models: evaluations
"""
from app import db
from app.models import UniteEns
import app.scodoc.notesdb as ndb
from app.scodoc import sco_evaluation_db
class Evaluation(db.Model):
"""Evaluation (contrôle, examen, ...)"""
__tablename__ = "notes_evaluation"
id = db.Column(db.Integer, primary_key=True)
evaluation_id = db.synonym("id")
moduleimpl_id = db.Column(
db.Integer, db.ForeignKey("notes_moduleimpl.id"), index=True
)
jour = db.Column(db.Date)
heure_debut = db.Column(db.Time)
heure_fin = db.Column(db.Time)
description = db.Column(db.Text)
note_max = db.Column(db.Float)
coefficient = db.Column(db.Float)
visibulletin = db.Column(
db.Boolean, nullable=False, default=True, server_default="true"
)
publish_incomplete = db.Column(
db.Boolean, nullable=False, default=False, server_default="false"
)
# type d'evaluation: 0 normale, 1 rattrapage, 2 "2eme session"
evaluation_type = db.Column(
db.Integer, nullable=False, default=0, server_default="0"
)
# ordre de presentation (par défaut, le plus petit numero
# est la plus ancienne eval):
numero = db.Column(db.Integer)
ues = db.relationship("UniteEns", secondary="evaluation_ue_poids", viewonly=True)
def __repr__(self):
return f"""<Evaluation {self.id} {self.jour.isoformat() if self.jour else ''} "{self.description[:16] if self.description else ''}">"""
def to_dict(self):
e = dict(self.__dict__)
e.pop("_sa_instance_state", None)
# ScoDoc7 output_formators
e["evaluation_id"] = self.id
e["jour"] = ndb.DateISOtoDMY(e["jour"])
e["numero"] = ndb.int_null_is_zero(e["numero"])
return sco_evaluation_db.evaluation_enrich_dict(e)
def from_dict(self, data):
"""Set evaluation attributes from given dict values."""
sco_evaluation_db._check_evaluation_args(data)
for k in self.__dict__.keys():
if k != "_sa_instance_state" and k != "id" and k in data:
setattr(self, k, data[k])
def clone(self, not_copying=()):
"""Clone, not copying the given attrs
Attention: la copie n'a pas d'id avant le prochain commit
"""
d = dict(self.__dict__)
d.pop("id") # get rid of id
d.pop("_sa_instance_state") # get rid of SQLAlchemy special attr
for k in not_copying:
d.pop(k)
copy = self.__class__(**d)
db.session.add(copy)
return copy
def set_ue_poids(self, ue, poids: float) -> None:
"""Set poids évaluation vers cette UE"""
self.update_ue_poids_dict({ue.id: poids})
def set_ue_poids_dict(self, ue_poids_dict: dict) -> None:
"""set poids vers les UE (remplace existants)
ue_poids_dict = { ue_id : poids }
"""
L = []
for ue_id, poids in ue_poids_dict.items():
ue = UniteEns.query.get(ue_id)
L.append(EvaluationUEPoids(evaluation=self, ue=ue, poids=poids))
self.ue_poids = L
self.moduleimpl.invalidate_evaluations_poids() # inval cache
def update_ue_poids_dict(self, ue_poids_dict: dict) -> None:
"""update poids vers UE (ajoute aux existants)"""
current = self.get_ue_poids_dict()
current.update(ue_poids_dict)
self.set_ue_poids_dict(current)
def get_ue_poids_dict(self) -> dict:
"""returns { ue_id : poids }"""
return {p.ue.id: p.poids for p in self.ue_poids}
def get_ue_poids_str(self) -> str:
"""string describing poids, for excel cells and pdfs
Note: si les poids ne sont pas initialisés (poids par défaut),
ils ne sont pas affichés.
"""
# restreint aux UE du semestre dans lequel est cette évaluation
# au cas où le module ait changé de semestre et qu'il reste des poids
evaluation_semestre_idx = self.moduleimpl.module.semestre_id
return ", ".join(
[
f"{p.ue.acronyme}: {p.poids}"
for p in self.ue_poids
if evaluation_semestre_idx == p.ue.semestre_idx
]
)
class EvaluationUEPoids(db.Model):
"""Poids des évaluations (BUT)
association many to many
"""
evaluation_id = db.Column(
db.Integer,
db.ForeignKey("notes_evaluation.id", ondelete="CASCADE"),
primary_key=True,
)
ue_id = db.Column(
db.Integer,
db.ForeignKey("notes_ue.id", ondelete="CASCADE"),
primary_key=True,
)
poids = db.Column(
db.Float,
nullable=False,
)
evaluation = db.relationship(
Evaluation,
backref=db.backref("ue_poids", cascade="all, delete-orphan"),
)
ue = db.relationship(
UniteEns,
backref=db.backref("evaluation_ue_poids", cascade="all, delete-orphan"),
)
def __repr__(self):
return f"<EvaluationUEPoids {self.evaluation} {self.ue} poids={self.poids}>"