From 976a559cca04cc3a3710bebe8c941c9f09f0177e Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Wed, 20 Jan 2016 17:49:12 +0100 Subject: [PATCH] Add export capability for class summary view --- stages/static/img/xls.png | Bin 0 -> 15431 bytes stages/views.py | 51 +++++++++++++++++++++++++++++++++++++- templates/class.html | 3 +++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 stages/static/img/xls.png diff --git a/stages/static/img/xls.png b/stages/static/img/xls.png new file mode 100644 index 0000000000000000000000000000000000000000..3b8d35361807c4ffc1304628714fccdf8609e9a5 GIT binary patch literal 15431 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 literal 0 HcmV?d00001 diff --git a/stages/views.py b/stages/views.py index 618c886..dd64d12 100644 --- a/stages/views.py +++ b/stages/views.py @@ -79,6 +79,52 @@ class KlassView(DetailView): ).prefetch_related('training_set').order_by('last_name', 'first_name') return context + def render_to_response(self, context, **response_kwargs): + if self.request.GET.get('format') != 'xls': + return super().render_to_response(context, **response_kwargs) + + from openpyxl import Workbook + from openpyxl.cell import get_column_letter + from openpyxl.styles import Font, Style + from openpyxl.writer.excel import save_virtual_workbook + + wb = Workbook() + ws = wb.get_active_sheet() + ws.title = self.object.name + bold = Style(font=Font(bold=True)) + headers = [ + 'Nom', 'Prénom', 'Domicile', 'Date de naissance', + 'Stage 1', 'Domaine 1', 'Stage 2', 'Domaine 2', 'Stage 3', 'Domaine 3', + ] + col_widths = [18, 15, 20, 14, 25, 12, 25, 12, 25, 12] + # Headers + for col_idx, header in enumerate(headers, start=1): + cell = ws.cell(row=1, column=col_idx) + cell.value = header + cell.style = bold + ws.column_dimensions[get_column_letter(col_idx)].width = col_widths[col_idx - 1] + # Data + for row_idx, student in enumerate(context['students'], start=2): + ws.cell(row=row_idx, column=1).value = student.last_name + ws.cell(row=row_idx, column=2).value = student.first_name + ws.cell(row=row_idx, column=3).value = " ".join([student.pcode, student.city]) + ws.cell(row=row_idx, column=4).value = student.birth_date + col_idx = 5 + for training in student.training_set.select_related( + 'availability', 'availability__corporation', 'availability__domain' + ).all(): + ws.cell(row=row_idx, column=col_idx).value = training.availability.corporation.name + ws.cell(row=row_idx, column=col_idx + 1).value = training.availability.domain.name + col_idx += 2 + + response = HttpResponse( + save_virtual_workbook(wb), + content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) + response['Content-Disposition'] = 'attachment; filename=%s_export_%s.xlsx' % ( + self.object.name.replace(' ', '_'), date.strftime(date.today(), '%Y-%m-%d')) + return response + class AttributionView(TemplateView): """ @@ -393,7 +439,10 @@ def stages_export(request, scope=None): [c.email for c in always_ccs[tr[corp_name_field]].get(tr[export_fields['Filière']])] ) - response = HttpResponse(save_virtual_workbook(wb), content_type='application/ms-excel') + response = HttpResponse( + save_virtual_workbook(wb), + content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ) response['Content-Disposition'] = 'attachment; filename=%s%s.xlsx' % ( 'stages_export_', date.strftime(date.today(), '%Y-%m-%d')) return response diff --git a/templates/class.html b/templates/class.html index be2af17..7ed5d9a 100644 --- a/templates/class.html +++ b/templates/class.html @@ -10,6 +10,9 @@ {% block content %}

{{ klass.name }}

+
+ +

Récapitulatif des stages

{% for student in students %}