2026-07-14 17:06:37 +00:00
|
|
|
"""
|
|
|
|
|
Utilitaires de parcours de l'arborescence de catégories (profondeur
|
|
|
|
|
illimitée). Partagés entre le routeur categories (affichage de l'arbre) et
|
|
|
|
|
le routeur materiels (construction du <select> indenté).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
from sqlmodel import Session, select
|
|
|
|
|
|
|
|
|
|
from app.models import Categorie
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def categories_racines(session: Session) -> list[Categorie]:
|
|
|
|
|
"""Catégories de premier niveau (sans parent)."""
|
|
|
|
|
return list(session.exec(select(Categorie).where(Categorie.parent_id.is_(None))).all())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def aplatir(categories: list[Categorie], profondeur: int = 0) -> list[tuple[int, Categorie]]:
|
|
|
|
|
"""Aplatit l'arborescence en une liste (profondeur, categorie), dans
|
|
|
|
|
l'ordre d'affichage (chaque nœud juste avant ses enfants). Sert à
|
|
|
|
|
construire un <select> indenté sans avoir besoin de JavaScript."""
|
|
|
|
|
resultat: list[tuple[int, Categorie]] = []
|
|
|
|
|
for categorie in categories:
|
|
|
|
|
resultat.append((profondeur, categorie))
|
|
|
|
|
resultat.extend(aplatir(categorie.enfants, profondeur + 1))
|
|
|
|
|
return resultat
|
2026-07-14 17:17:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def ids_sous_arbre(categorie: Categorie) -> set[int]:
|
|
|
|
|
"""L'id de cette catégorie et de tous ses descendants, à n'importe
|
|
|
|
|
quelle profondeur. Sert au filtre "cette catégorie" sur /materiels :
|
|
|
|
|
on veut aussi les matériels rattachés à ses sous-catégories, pas
|
|
|
|
|
seulement à elle-même."""
|
|
|
|
|
ids = {categorie.id}
|
|
|
|
|
for enfant in categorie.enfants:
|
|
|
|
|
ids |= ids_sous_arbre(enfant)
|
|
|
|
|
return ids
|