0
0
mirror of https://github.com/wagtail/wagtail.git synced 2024-12-01 11:41:20 +01:00

Change order of export fields & Update mixins

Makes the export file easier to import as the first two columns are used by default in the import command
This commit is contained in:
Jaap Roes 2022-07-06 17:10:27 +02:00 committed by LB (Ben Johnston)
parent 07adb156d1
commit c5a6eded96
4 changed files with 67 additions and 48 deletions

View File

@ -142,6 +142,9 @@ class TestLockedPagesView(TestCase, WagtailTestUtils):
)
self.assertEqual(len(cell_array), 2)
self.assertEqual(worksheet["B2"].number_format, ExcelDateFormatter().get())
self.assertEqual(worksheet["E2"].number_format, ExcelDateFormatter().get())
class TestFilteredLockedPagesView(TestCase, WagtailTestUtils):
fixtures = ["test.json"]
@ -407,6 +410,8 @@ class TestAgingPagesView(TestCase, WagtailTestUtils):
)
self.assertEqual(len(cell_array), 2)
self.assertEqual(worksheet["C2"].number_format, ExcelDateFormatter().get())
class TestFilteredAgingPagesView(TestCase, WagtailTestUtils):
fixtures = ["test.json"]

View File

@ -1,13 +1,16 @@
import csv
import datetime
from collections import OrderedDict
from io import BytesIO
from django.core.exceptions import FieldDoesNotExist
from django.http import HttpResponse, StreamingHttpResponse
from django.http import FileResponse, StreamingHttpResponse
from django.utils import timezone
from django.utils.dateformat import Formatter
from django.utils.encoding import force_str
from django.utils.formats import get_format
from xlsxwriter.workbook import Workbook
from openpyxl import Workbook
from openpyxl.cell import WriteOnlyCell
from wagtail.coreutils import multigetattr
@ -136,6 +139,13 @@ class SpreadsheetExportMixin:
custom_field_preprocess = {}
# A dictionary of preprocessing functions by value class and format
custom_value_preprocess = {
datetime.datetime: {
FORMAT_XLSX: lambda value: (
value
if timezone.is_naive(value)
else timezone.make_naive(value, timezone.utc)
)
},
(datetime.date, datetime.time): {FORMAT_XLSX: None},
list: {FORMAT_CSV: list_to_str, FORMAT_XLSX: list_to_str},
}
@ -169,27 +179,31 @@ class SpreadsheetExportMixin:
# Finally resort to force_str to prevent encoding errors
return force_str
def write_xlsx_row(self, worksheet, row_dict, row_number):
for col_number, (field, value) in enumerate(row_dict.items()):
preprocess_function = self.get_preprocess_function(
field, value, self.FORMAT_XLSX
def preprocess_field_value(self, field, value, export_format):
"""Preprocesses a field value before writing it to the spreadsheet"""
preprocess_function = self.get_preprocess_function(field, value, export_format)
if preprocess_function is not None:
return preprocess_function(value)
else:
return value
def generate_xlsx_row(self, worksheet, row_dict, date_format=None):
"""Generate cells to append to the worksheet"""
for field, value in row_dict.items():
cell = WriteOnlyCell(
worksheet, self.preprocess_field_value(field, value, self.FORMAT_XLSX)
)
processed_value = (
preprocess_function(value) if preprocess_function else value
)
worksheet.write(row_number, col_number, processed_value)
if date_format and isinstance(value, datetime.datetime):
cell.number_format = date_format
yield cell
def write_csv_row(self, writer, row_dict):
processed_row = {}
for field, value in row_dict.items():
preprocess_function = self.get_preprocess_function(
field, value, self.FORMAT_CSV
)
processed_value = (
preprocess_function(value) if preprocess_function else value
)
processed_row[field] = processed_value
return writer.writerow(processed_row)
return writer.writerow(
{
field: self.preprocess_field_value(field, value, self.FORMAT_CSV)
for field, value in row_dict.items()
}
)
def get_heading(self, queryset, field):
"""Get the heading label for a given field for a spreadsheet generated from queryset"""
@ -213,35 +227,35 @@ class SpreadsheetExportMixin:
def write_xlsx(self, queryset, output):
"""Write an xlsx workbook from a queryset"""
workbook = Workbook(
output,
{
"in_memory": True,
"constant_memory": True,
"remove_timezone": True,
"default_date_format": ExcelDateFormatter().get(),
},
workbook = Workbook(write_only=True, iso_dates=True)
worksheet = workbook.create_sheet(title="Sheet1")
worksheet.append(
self.get_heading(queryset, field) for field in self.list_export
)
worksheet = workbook.add_worksheet()
for col_number, field in enumerate(self.list_export):
worksheet.write(0, col_number, self.get_heading(queryset, field))
date_format = ExcelDateFormatter().get()
for item in queryset:
worksheet.append(
self.generate_xlsx_row(
worksheet, self.to_row_dict(item), date_format=date_format
)
)
for row_number, item in enumerate(queryset):
self.write_xlsx_row(worksheet, self.to_row_dict(item), row_number + 1)
workbook.close()
workbook.save(output)
def write_xlsx_response(self, queryset):
response = HttpResponse(
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
response["Content-Disposition"] = 'attachment; filename="{}.xlsx"'.format(
self.get_filename()
)
self.write_xlsx(queryset, response)
"""Write an xlsx file from a queryset and return a FileResponse"""
output = BytesIO()
self.write_xlsx(queryset, output)
output.seek(0)
return response
return FileResponse(
output,
as_attachment=True,
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
filename=f"{self.get_filename()}.xlsx",
)
def write_csv_response(self, queryset):
stream = self.stream_csv(queryset)

View File

@ -63,9 +63,9 @@ class TestRedirectReport(TestCase, WagtailTestUtils):
csv_entries = csv_data[1:]
csv_entries = csv_entries[:-1] # Drop empty last line
self.assertEqual(csv_header, "From,Site,To,Type\r")
self.assertEqual(csv_header, "From,To,Type,Site\r")
self.assertEqual(len(csv_entries), 1)
self.assertEqual(csv_entries[0], "/from,None,/to,temporary\r")
self.assertEqual(csv_entries[0], "/from,/to,temporary,None\r")
def test_xlsx_export(self):
Redirect.add_redirect("/from", "/to", True)
@ -77,6 +77,6 @@ class TestRedirectReport(TestCase, WagtailTestUtils):
worksheet = load_workbook(filename=BytesIO(workbook_data))["Sheet1"]
cell_array = [[cell.value for cell in row] for row in worksheet.rows]
self.assertEqual(cell_array[0], ["From", "Site", "To", "Type"])
self.assertEqual(cell_array[0], ["From", "To", "Type", "Site"])
self.assertEqual(len(cell_array), 2)
self.assertEqual(cell_array[1], ["/from", "None", "/to", "permanent"])
self.assertEqual(cell_array[1], ["/from", "/to", "permanent", "None"])

View File

@ -411,9 +411,9 @@ class RedirectsReportView(ReportView):
list_export = [
"old_path",
"site",
"link",
"get_is_permanent_display",
"site",
]
export_headings = {