Tableau recap: export xls. (et abandon de l'export CSV).
This commit is contained in:
parent
e4ab0d5885
commit
a9696fe598
@ -334,9 +334,7 @@ def do_formsemestre_archive(
|
||||
etudids = [m["etudid"] for m in groups_infos.members]
|
||||
|
||||
# Tableau recap notes en XLS (pour tous les etudiants, n'utilise pas les groupes)
|
||||
data, _ = gen_formsemestre_recapcomplet_excel(
|
||||
formsemestre, res, include_evaluations=True, format="xls"
|
||||
)
|
||||
data, _ = gen_formsemestre_recapcomplet_excel(res, include_evaluations=True)
|
||||
if data:
|
||||
PVArchive.store(archive_id, "Tableau_moyennes" + scu.XLSX_SUFFIX, data)
|
||||
# Tableau recap notes en HTML (pour tous les etudiants, n'utilise pas les groupes)
|
||||
|
@ -194,12 +194,12 @@ class ScoExcelSheet:
|
||||
* pour finir appel de la méthode de génération
|
||||
"""
|
||||
|
||||
def __init__(self, sheet_name="feuille", default_style=None, wb=None):
|
||||
def __init__(self, sheet_name="feuille", default_style=None, wb: Workbook = None):
|
||||
"""Création de la feuille. sheet_name
|
||||
-- le nom de la feuille default_style
|
||||
-- le style par défaut des cellules ws
|
||||
-- None si la feuille est autonome (dans ce cas ell crée son propre wb), sinon c'est la worksheet
|
||||
créée par le workbook propriétaire un workbook est crée et associé à cette feuille.
|
||||
-- None si la feuille est autonome (dans ce cas elle crée son propre wb), sinon c'est la worksheet
|
||||
créée par le workbook propriétaire un workbook est créé et associé à cette feuille.
|
||||
"""
|
||||
# Le nom de la feuille ne peut faire plus de 31 caractères.
|
||||
# si la taille du nom de feuille est > 31 on tronque (on pourrait remplacer par 'feuille' ?)
|
||||
|
@ -225,16 +225,14 @@ def _do_formsemestre_recapcomplet(
|
||||
selected_etudid=selected_etudid,
|
||||
)
|
||||
return data
|
||||
elif format.startswith("xls") or format == "csv":
|
||||
elif format.startswith("xls"):
|
||||
res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
|
||||
include_evaluations = format in {"xlsall", "csv "}
|
||||
include_evaluations = format in {"xlsall", "csv "} # csv not supported anymore
|
||||
if format != "csv":
|
||||
format = "xlsx"
|
||||
data, filename = gen_formsemestre_recapcomplet_excel(
|
||||
formsemestre,
|
||||
res,
|
||||
include_evaluations=include_evaluations,
|
||||
format=format,
|
||||
filename=filename,
|
||||
)
|
||||
return scu.send_file(data, filename=filename, mime=scu.get_mime_suffix(format))
|
||||
@ -446,33 +444,22 @@ def _gen_formsemestre_recapcomplet_html(
|
||||
|
||||
|
||||
def gen_formsemestre_recapcomplet_excel(
|
||||
formsemestre: FormSemestre,
|
||||
res: NotesTableCompat,
|
||||
include_evaluations=False,
|
||||
filename: str = "",
|
||||
format="xls",
|
||||
) -> tuple:
|
||||
"""Génère le tableau recap en excel (xlsx) ou CSV.
|
||||
"""Génère le tableau recap en excel (xlsx).
|
||||
Utilisé pour archives et autres besoins particuliers (API).
|
||||
Attention: le tableau exporté depuis la page html est celui généré en js par DataTables,
|
||||
et non celui-ci.
|
||||
"""
|
||||
suffix = scu.CSV_SUFFIX if format == "csv" else scu.XLSX_SUFFIX
|
||||
filename += suffix
|
||||
filename += scu.XLSX_SUFFIX
|
||||
|
||||
# XXX TODO A ADAPTER XXX !!! !!!
|
||||
table = TableRecap(
|
||||
res,
|
||||
convert_values=False,
|
||||
include_evaluations=include_evaluations,
|
||||
preferences=sco_preferences.SemPreferences(formsemestre_id=formsemestre.id),
|
||||
# preferences=sco_preferences.SemPreferences(formsemestre_id=formsemestre.id),
|
||||
)
|
||||
|
||||
# tab = GenTable(
|
||||
# columns_ids=column_ids,
|
||||
# titles=titles,
|
||||
# rows=rows + footer_rows,
|
||||
# preferences=sco_preferences.SemPreferences(formsemestre_id=formsemestre.id),
|
||||
# )
|
||||
|
||||
return table.gen(format=format), filename
|
||||
return table.excel(), filename
|
||||
|
@ -8,8 +8,15 @@
|
||||
"""
|
||||
from collections import defaultdict
|
||||
|
||||
from openpyxl import Workbook
|
||||
from openpyxl.utils import get_column_letter
|
||||
|
||||
from app.scodoc import sco_excel
|
||||
|
||||
|
||||
class Element:
|
||||
"Element de base pour les tables"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
elt: str,
|
||||
@ -49,18 +56,6 @@ class Element:
|
||||
class Table(Element):
|
||||
"""Construction d'une table de résultats
|
||||
|
||||
table = Table()
|
||||
row = table.new_row(id="xxx", category="yyy")
|
||||
row.new_cell( col_id, title, content [,classes] [, idx], [group], [keys:dict={}] )
|
||||
|
||||
rows = table.get_rows([category="yyy"])
|
||||
table.sort_rows(key [, reverse])
|
||||
table.set_titles(titles)
|
||||
table.update_titles(titles)
|
||||
|
||||
table.set_column_groups(groups: list[str])
|
||||
table.insert_group(group:str, [after=str], [before=str])
|
||||
|
||||
Ordre des colonnes: groupées par groupes, et dans chaque groupe par ordre d'insertion
|
||||
On fixe l'ordre des groupes par ordre d'insertion
|
||||
ou par insert_group ou par set_column_groups.
|
||||
@ -74,6 +69,12 @@ class Table(Element):
|
||||
attrs: dict[str, str] = None,
|
||||
data: dict = None,
|
||||
row_class=None,
|
||||
xls_sheet_name="feuille",
|
||||
xls_before_table=[], # liste de cellules a placer avant la table
|
||||
xls_style_base=None, # style excel pour les cellules
|
||||
xls_columns_width=None, # { col_id : largeur en "pixels excel" }
|
||||
caption="",
|
||||
origin="",
|
||||
):
|
||||
super().__init__("table", classes=classes, attrs=attrs, data=data)
|
||||
self.row_class = row_class or Row
|
||||
@ -103,6 +104,14 @@ class Table(Element):
|
||||
self, "title_foot", cell_elt="th", classes=["titles"]
|
||||
)
|
||||
self.empty_cell = Cell.empty()
|
||||
# Excel (xls) spécifique:
|
||||
self.xls_before_table = xls_before_table
|
||||
self.xls_columns_width = xls_columns_width or {}
|
||||
self.xls_sheet_name = xls_sheet_name
|
||||
self.xls_style_base = xls_style_base
|
||||
#
|
||||
self.caption = caption
|
||||
self.origin = origin
|
||||
|
||||
def _prepare(self):
|
||||
"""Prepare the table before generation:
|
||||
@ -130,7 +139,7 @@ class Table(Element):
|
||||
self.selected_row_id = row_id
|
||||
|
||||
def to_list(self) -> list[dict]:
|
||||
"""as a list, each row is a dict"""
|
||||
"""as a list, each row is a dict (sans les lignes d'en-tête ni de pied de table)"""
|
||||
self._prepare()
|
||||
return [row.to_dict() for row in self.rows]
|
||||
|
||||
@ -265,6 +274,45 @@ class Table(Element):
|
||||
|
||||
return self.head_title_row.cells.get(col_id), self.foot_title_row.cells[col_id]
|
||||
|
||||
def excel(self, wb: Workbook = None):
|
||||
"""Simple Excel representation of the table."""
|
||||
self._prepare()
|
||||
if wb is None:
|
||||
sheet = sco_excel.ScoExcelSheet(sheet_name=self.xls_sheet_name, wb=wb)
|
||||
else:
|
||||
sheet = wb.create_sheet(sheet_name=self.xls_sheet_name)
|
||||
sheet.rows += self.xls_before_table
|
||||
style_bold = sco_excel.excel_make_style(bold=True)
|
||||
style_base = self.xls_style_base or sco_excel.excel_make_style()
|
||||
|
||||
for row in self.head:
|
||||
sheet.append_row(row.to_excel(sheet, style=style_bold))
|
||||
|
||||
for row in self.rows:
|
||||
sheet.append_row(row.to_excel(sheet, style=style_base))
|
||||
|
||||
for row in self.foot:
|
||||
sheet.append_row(row.to_excel(sheet, style=style_base))
|
||||
|
||||
if self.caption:
|
||||
sheet.append_blank_row() # empty line
|
||||
sheet.append_single_cell_row(self.caption, style_base)
|
||||
if self.origin:
|
||||
sheet.append_blank_row() # empty line
|
||||
sheet.append_single_cell_row(self.origin, style_base)
|
||||
|
||||
# Largeurs des colonnes
|
||||
for col_id, width in self.xls_columns_width.items():
|
||||
try:
|
||||
idx = self.column_ids.index(col_id)
|
||||
col = get_column_letter(idx + 1)
|
||||
sheet.set_column_dimension_width(col, width)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if wb is None:
|
||||
return sheet.generate()
|
||||
|
||||
|
||||
class Row(Element):
|
||||
"""A row."""
|
||||
@ -371,6 +419,10 @@ class Row(Element):
|
||||
for col_id in self.table.column_ids
|
||||
}
|
||||
|
||||
def to_excel(self, sheet, style=None) -> list:
|
||||
"build excel row for given sheet"
|
||||
return sheet.make_row(self.to_dict().values(), style=style)
|
||||
|
||||
|
||||
class BottomRow(Row):
|
||||
"""Une ligne spéciale pour le pied de table
|
||||
|
Loading…
Reference in New Issue
Block a user