Assiduites : fin intégration pagination + cache tableau

This commit is contained in:
Iziram 2024-01-16 09:19:40 +01:00
parent 89a16489bc
commit c0f26e952a
6 changed files with 56 additions and 105 deletions

View File

@ -758,4 +758,7 @@ def simple_invalidate_cache(obj: dict, etudid: str | int = None):
invalidate_assiduites_etud_date(etudid, date_debut) invalidate_assiduites_etud_date(etudid, date_debut)
invalidate_assiduites_etud_date(etudid, date_fin) invalidate_assiduites_etud_date(etudid, date_fin)
sco_cache.RequeteTableauAssiduiteCache.delete_with(f"tableau-etud-{etudid}") # Invalide les caches des tableaux de l'étudiant
sco_cache.RequeteTableauAssiduiteCache.delete_pattern(
pattern=f"tableau-etud-{etudid}:*"
)

View File

@ -398,10 +398,6 @@ class ValidationsSemestreCache(ScoDocCache):
timeout = 60 * 60 # ttl 1 heure (en phase de mise au point) timeout = 60 * 60 # ttl 1 heure (en phase de mise au point)
class SimpleIndexCache(ScoDocCache):
prefix = "INDEX"
class RequeteTableauAssiduiteCache(ScoDocCache): class RequeteTableauAssiduiteCache(ScoDocCache):
""" """
clé : "<titre_tableau>:<type_obj>:<show_pres>:<show_retard>>:<order_col>:<order>" clé : "<titre_tableau>:<type_obj>:<show_pres>:<show_retard>>:<order_col>:<order>"
@ -410,42 +406,3 @@ class RequeteTableauAssiduiteCache(ScoDocCache):
prefix = "TABASSI" prefix = "TABASSI"
timeout = 60 * 60 # Une heure timeout = 60 * 60 # Une heure
@classmethod
def set(cls, oid: str, value: object):
"""Ajoute une entrée au cache. Ajoute la clé dans la liste des clés du cache"""
keys_index = cls.get_index()
# On met à jour l'index
if oid not in keys_index:
keys_index.append(oid)
SimpleIndexCache.set(cls.prefix + "_index", keys_index)
# On cache la valeur
return super().set(oid, value)
@classmethod
def get_index(cls) -> list:
"""récupère la liste des clés des entrées du cache"""
# on définie un index des clés pour faciliter l'invalidation
keys_index: list = SimpleIndexCache.get(cls.prefix + "_index")
if keys_index is None:
keys_index = []
return keys_index
@classmethod
def delete_with(cls, start: str):
"""Invalide toutes les entrées de cache commençant par <start>"""
keys_index: list[str] = cls.get_index()
key: str
filtered_keys_index: list = [key for key in keys_index if key.startswith(start)]
for key in filtered_keys_index:
cls.delete(key)
SimpleIndexCache.set(
cls.prefix + "_index",
[k for k in keys_index if k not in filtered_keys_index],
)

View File

@ -1,51 +1,3 @@
function loadAssi(count, deb) {
let c = 0;
let a = new Date(deb);
a.setHours(0, 0, 0, 0);
const etat = ["present", "absent", "retard"];
const etudid = 17888;
const path = getUrl() + `/api/assiduite/${etudid}/create`;
const assiduites = [];
while (c < count) {
if (a.getDay() > 0 && a.getDay() < 6) {
c++;
const date = a.toISOString().split("T")[0];
const assis = [
{
date_debut: date + "T08:00",
date_fin: date + "T10:00",
etat: etat[Math.floor(Math.random() * 3)],
},
{
date_debut: date + "T10:15",
date_fin: date + "T12:15",
etat: etat[Math.floor(Math.random() * 3)],
},
{
date_debut: date + "T13:15",
date_fin: date + "T15:15",
etat: etat[Math.floor(Math.random() * 3)],
},
{
date_debut: date + "T15:30",
date_fin: date + "T17:00",
etat: etat[Math.floor(Math.random() * 3)],
},
];
assiduites.push(...assis);
}
a = new Date(a.valueOf() + 24 * 3600 * 1000);
}
async_post(
path,
assiduites,
() => {},
() => {}
);
}
// <=== CONSTANTS and GLOBALS ===> // <=== CONSTANTS and GLOBALS ===>
let url; let url;

View File

@ -13,20 +13,61 @@ from app.scodoc.sco_cache import RequeteTableauAssiduiteCache
class Pagination: class Pagination:
"""
Pagination d'une collection de données
On donne :
- une collection de données (de préférence une liste / tuple)
- le numéro de page à afficher
- le nombre d'éléments par page
On peut ensuite récupérer les éléments de la page courante avec la méthode `items()`
Cette classe ne permet pas de changer de page.
(Pour cela, il faut créer une nouvelle instance, avec la collection originelle et la nouvelle page)
l'intéret est de ne pas garder en mémoire toute la collection, mais seulement la page courante
"""
def __init__(self, collection: list, page: int = 1, per_page: int = -1): def __init__(self, collection: list, page: int = 1, per_page: int = -1):
"""
__init__ Instancie un nouvel objet Pagination
Args:
collection (list): La collection à paginer. Il s'agit par exemple d'une requête
page (int, optional): le numéro de la page à voir. Defaults to 1.
per_page (int, optional): le nombre d'éléments par page. Defaults to -1. (-1 = pas de pagination/tout afficher)
"""
# par défaut le total des pages est 1 (même si la collection est vide)
self.total_pages = 1 self.total_pages = 1
if per_page != -1: if per_page != -1:
# on récupère le nombre de page complète et le reste
# q => nombre de page
# r => le nombre d'éléments restants (dernière page si != 0)
q, r = len(collection) // per_page, len(collection) % per_page q, r = len(collection) // per_page, len(collection) % per_page
self.total_pages = q if r == 0 else q + 1 self.total_pages = q if r == 0 else q + 1 # q + 1 s'il reste des éléments
current_page: int = min(self.total_pages, page)
# On s'assure que la page demandée est dans les limites
current_page: int = min(self.total_pages, page if page > 0 else 1)
# On récupère la collection de la page courante
self.collection = ( self.collection = (
collection collection # toute la collection si pas de pagination
if per_page == -1 if per_page == -1
else collection[per_page * (current_page - 1) : per_page * (current_page)] else collection[
per_page * (current_page - 1) : per_page * (current_page)
] # sinon on récupère la page
) )
def items(self) -> list: def items(self) -> list:
"""
items Renvoi la collection de la page courante
Returns:
list: la collection de la page courante
"""
return self.collection return self.collection

View File

@ -47,7 +47,8 @@
</li> </li>
<!-- Afficher les ellipses si la page courante est supérieure à 2 --> <!-- Afficher les ellipses si la page courante est supérieure à 2 -->
{% if options.page > 2 %} <!-- et qu'il y a plus d'une page entre le 1 et la page courante-1 -->
{% if options.page > 2 and (options.page - 1) - 1 > 1 %}
<li class="disabled"><span>...</span></li> <li class="disabled"><span>...</span></li>
{% endif %} {% endif %}
@ -61,7 +62,8 @@
{% endfor %} {% endfor %}
<!-- Afficher les ellipses si la page courante est inférieure à l'avant-dernière page --> <!-- Afficher les ellipses si la page courante est inférieure à l'avant-dernière page -->
{% if options.page < total_pages - 1 %} <!-- et qu'il y a plus d'une page entre le total_pages et la page courante+1 -->
{% if options.page < total_pages - 1 and total_pages - (options.page + 1 ) > 1 %}
<li class="disabled"><span>...</span></li> <li class="disabled"><span>...</span></li>
{% endif %} {% endif %}

View File

@ -525,11 +525,11 @@ def liste_assiduites_etud():
liste_assi.AssiJustifData.from_etudiants( liste_assi.AssiJustifData.from_etudiants(
etud, etud,
), ),
filename=f"assiduites-justificatifs-{etudid}", filename=f"assiduites-justificatifs-{etud.id}",
afficher_etu=False, afficher_etu=False,
filtre=liste_assi.AssiFiltre(type_obj=0), filtre=liste_assi.AssiFiltre(type_obj=0),
options=liste_assi.AssiDisplayOptions(show_module=True), options=liste_assi.AssiDisplayOptions(show_module=True),
cache_key=f"tableau-etud-{etudid}", cache_key=f"tableau-etud-{etud.id}",
) )
if not tableau[0]: if not tableau[0]:
return tableau[1] return tableau[1]
@ -1501,9 +1501,6 @@ def _prepare_tableau(
show_etu=afficher_etu, show_etu=afficher_etu,
order=ordre, order=ordre,
) )
import time
a = time.time()
table: liste_assi.ListeAssiJusti = liste_assi.ListeAssiJusti( table: liste_assi.ListeAssiJusti = liste_assi.ListeAssiJusti(
table_data=data, table_data=data,
@ -1512,8 +1509,7 @@ def _prepare_tableau(
no_pagination=fmt.startswith("xls"), no_pagination=fmt.startswith("xls"),
titre=cache_key, titre=cache_key,
) )
b = time.time()
print(f"génération du tableau : {b-a:.6f}s")
if fmt.startswith("xls"): if fmt.startswith("xls"):
return False, scu.send_file( return False, scu.send_file(
table.excel(), table.excel(),