perf: paginer/agréger les pages acheteur et titulaire côté DuckDB

Les pages acheteur/titulaire chargeaient l'intégralité des marchés d'une
organisation dans un dcc.Store côté client (jusqu'à 16k lignes pour les
plus gros acheteurs), envoyée sur le réseau à chaque interaction. Le
tableau, le top 10 et l'histogramme des distances récupèrent maintenant
leurs données via des requêtes DuckDB scopées (pagination/agrégation
poussées en SQL), sur le modèle déjà utilisé par la page tableau.

Corrige aussi le CLS des mêmes pages en réservant l'espace des
conteneurs remplis par callback (carte, top 10, histogramme).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Colin Maudry
2026-07-01 13:46:44 +02:00
parent 8515ba8d84
commit a2c20adb4e
5 changed files with 179 additions and 119 deletions
+23 -3
View File
@@ -427,9 +427,14 @@ def _fetch_page_sql(
sort_by_key: tuple,
page_current: int,
page_size: int,
base_where_sql: str = "TRUE",
base_params: tuple = (),
) -> tuple[pl.DataFrame, int, int]:
"""Chemin rapide : filtre/tri/pagine dans DuckDB, post-traite la page seule.
`base_where_sql`/`base_params` permettent de scoper la requête (ex : un
acheteur ou un titulaire précis) en plus du filtre saisi dans la table.
Retourne (page_dataframe_post_traitée, total_count, total_unique_count).
"""
# Import local pour éviter une dépendance circulaire
@@ -441,7 +446,9 @@ def _fetch_page_sql(
f"page={page_current} size={page_size}"
)
where_sql, params = filter_query_to_sql(filter_query or "", schema)
filter_where_sql, filter_params = filter_query_to_sql(filter_query or "", schema)
where_sql = f"({base_where_sql}) AND ({filter_where_sql})"
params = [*base_params, *filter_params]
sort_by_dash = [
{"column_id": col, "direction": direction} for col, direction in sort_by_key
@@ -464,7 +471,15 @@ def _fetch_page_sql(
def prepare_table_data(
data, data_timestamp, filter_query, page_current, page_size, sort_by, source_table
data,
data_timestamp,
filter_query,
page_current,
page_size,
sort_by,
source_table,
base_where_sql: str = "TRUE",
base_params: tuple = (),
):
"""
Fonction de préparation des données pour les datatables, afin de permettre une gestion fine des logiques,
@@ -476,6 +491,8 @@ def prepare_table_data(
:param page_size:
:param sort_by:
:param source_table:
:param base_where_sql: scope SQL additionnel (ex : un acheteur/titulaire précis)
:param base_params: paramètres liés à base_where_sql
:return:
"""
logger.debug(" + + + + + + + + + + + + + + + + + + ")
@@ -486,13 +503,16 @@ def prepare_table_data(
trigger_cleanup = no_update if source_table == "tableau" else str(uuid.uuid4())
if data is None:
# Probablement car il s'agit de la page Tableau
# Chemin rapide SQL : tableau, acheteur, titulaire (scope éventuel via
# base_where_sql/base_params)
sort_by_key = normalize_sort_by(sort_by)
dff, height, total_unique = _fetch_page_sql(
filter_query=filter_query,
sort_by_key=sort_by_key,
page_current=page_current,
page_size=page_size,
base_where_sql=base_where_sql,
base_params=tuple(base_params),
)
else:
if isinstance(data, list):