diff --git a/wagtail/contrib/forms/templates/wagtailforms/index_submissions.html b/wagtail/contrib/forms/templates/wagtailforms/index_submissions.html index 65cbe6caa7..7e1f7d4d70 100644 --- a/wagtail/contrib/forms/templates/wagtailforms/index_submissions.html +++ b/wagtail/contrib/forms/templates/wagtailforms/index_submissions.html @@ -102,7 +102,7 @@
- +
diff --git a/wagtail/contrib/forms/views.py b/wagtail/contrib/forms/views.py index ac938d6b95..dad01da995 100644 --- a/wagtail/contrib/forms/views.py +++ b/wagtail/contrib/forms/views.py @@ -1,6 +1,8 @@ import csv import datetime +from collections import OrderedDict + from django.core.exceptions import PermissionDenied from django.core.paginator import InvalidPage from django.http import HttpResponse @@ -10,6 +12,7 @@ from django.utils.translation import ungettext from django.views.generic import ListView, TemplateView from wagtail.admin import messages +from wagtail.admin.views.reports import SpreadsheetExportMixin from wagtail.contrib.forms.forms import SelectDateForm from wagtail.contrib.forms.utils import get_forms_for_user from wagtail.core.models import Page @@ -131,7 +134,7 @@ class DeleteSubmissionsView(TemplateView): return context -class SubmissionsListView(SafePaginateListView): +class SubmissionsListView(SpreadsheetExportMixin, SafePaginateListView): """ Lists submissions for the provided form page """ template_name = 'wagtailforms/index_submissions.html' context_object_name = 'submissions' @@ -149,9 +152,13 @@ class SubmissionsListView(SafePaginateListView): if not get_forms_for_user(request.user).filter(pk=self.form_page.id).exists(): raise PermissionDenied - self.is_csv_export = (self.request.GET.get('action') == 'CSV') - if self.is_csv_export: + self.is_export = (self.request.GET.get('action') == 'export') + if self.is_export: self.paginate_by = None + data_fields = self.form_page.get_data_fields() + # Set the export fields and the headings for spreadsheet export + self.list_export = [field for field, label in data_fields] + self.export_heading_overrides = dict(data_fields) return super().dispatch(request, *args, **kwargs) @@ -174,7 +181,7 @@ class SubmissionsListView(SafePaginateListView): def get_paginate_by(self, queryset): """ Get the number of items to paginate by, or ``None`` for no pagination """ - if self.is_csv_export: + if self.is_export: return None return self.paginate_by @@ -182,7 +189,7 @@ class SubmissionsListView(SafePaginateListView): """ Return a dict of field names with ordering labels if ordering is valid """ orderable_fields = self.orderable_fields or () ordering = dict() - if self.is_csv_export: + if self.is_export: # Revert to CSV order_by submit_time ascending for backwards compatibility default_ordering = self.ordering_csv or () else: @@ -225,50 +232,30 @@ class SubmissionsListView(SafePaginateListView): result['submit_time__gte'] = date_from return result - def get_csv_filename(self): - """ Returns the filename for the generated CSV file """ - return 'export-{}.csv'.format( + def get_filename(self): + """ Returns the base filename for the generated spreadsheet data file """ + return 'export-{}'.format( datetime.datetime.today().strftime('%Y-%m-%d') ) - def get_csv_response(self, context): - """ Returns a CSV response """ - filename = self.get_csv_filename() - response = HttpResponse(content_type='text/csv; charset=utf-8') - response['Content-Disposition'] = 'attachment;filename={}'.format(filename) - - writer = csv.writer(response) - writer.writerow(context['data_headings']) - for data_row in context['data_rows']: - writer.writerow(data_row) - return response - def render_to_response(self, context, **response_kwargs): - if self.is_csv_export: - return self.get_csv_response(context) + if self.is_export: + return self.as_spreadsheet(context['submissions']) return super().render_to_response(context, **response_kwargs) + def to_row_dict(self, item): + """ Orders the submission dictionary for spreadsheet writing """ + row_dict = OrderedDict((field, item.get_data().get(field)) for field in self.list_export) + return row_dict + def get_context_data(self, **kwargs): - """ Return context for view, handle CSV or normal output """ + """ Return context for view """ context = super().get_context_data(**kwargs) submissions = context[self.context_object_name] data_fields = self.form_page.get_data_fields() data_rows = [] - - if self.is_csv_export: - # Build data_rows as list of lists containing formatted data values - # Using smart_str prevents UnicodeEncodeError for values with non-ansi symbols - for submission in submissions: - form_data = submission.get_data() - data_row = [] - for name, label in data_fields: - val = form_data.get(name) - if isinstance(val, list): - val = ', '.join(val) - data_row.append(smart_str(val)) - data_rows.append(data_row) - data_headings = [smart_str(label) for name, label in data_fields] - else: + context['submissions'] = submissions + if not self.is_export: # Build data_rows as list of dicts containing model_id and fields for submission in submissions: form_data = submission.get_data() @@ -300,12 +287,11 @@ class SubmissionsListView(SafePaginateListView): 'order': order_label, }) - context.update({ - 'form_page': self.form_page, - 'select_date_form': self.select_date_form, - 'data_headings': data_headings, - 'data_rows': data_rows, - 'submissions': submissions, - }) + context.update({ + 'form_page': self.form_page, + 'select_date_form': self.select_date_form, + 'data_headings': data_headings, + 'data_rows': data_rows, + }) return context