Add generic "download results as XLSX" feature

This commit is contained in:
Lance Edgar 2018-01-26 14:24:06 -06:00
parent eaad87c704
commit e5c5a071f2
2 changed files with 65 additions and 1 deletions

View file

@ -72,6 +72,9 @@
% if master.results_downloadable_csv and request.has_perm('{}.results_csv'.format(permission_prefix)):
<li>${h.link_to("Download results as CSV", url('{}.results_csv'.format(route_prefix)))}</li>
% endif
% if master.results_downloadable_xlsx and request.has_perm('{}.results_xlsx'.format(permission_prefix)):
<li>${h.link_to("Download results as XLSX", url('{}.results_xlsx'.format(route_prefix)))}</li>
% endif
% if master.creatable and request.has_perm('{}.create'.format(permission_prefix)):
% if master.creates_multiple:
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>

View file

@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
# Copyright © 2010-2017 Lance Edgar
# Copyright © 2010-2018 Lance Edgar
#
# This file is part of Rattail.
#
@ -41,6 +41,8 @@ from rattail.util import prettify
from rattail.time import localtime #, make_utc
from rattail.threads import Thread
from rattail.csvutil import UnicodeDictWriter
from rattail.files import temp_path
from rattail.excel import ExcelWriter
import formalchemy as fa
from pyramid import httpexceptions
@ -66,6 +68,7 @@ class MasterView(View):
listable = True
results_downloadable_csv = False
results_downloadable_xlsx = False
creatable = True
viewable = True
editable = True
@ -1472,6 +1475,57 @@ class MasterView(View):
response.content_disposition = b'attachment; filename={}.csv'.format(self.get_grid_key())
return response
def results_xlsx(self):
"""
Download current list results as XLSX.
"""
results = self.get_effective_data()
fields = self.get_xlsx_fields()
path = temp_path(suffix='.xlsx')
writer = ExcelWriter(path, fields, sheet_title=self.get_model_title_plural())
writer.write_header()
rows = []
for obj in results:
data = self.get_xlsx_row(obj, fields)
row = [data[field] for field in fields]
rows.append(row)
writer.write_rows(rows)
writer.auto_freeze()
writer.auto_filter()
writer.save()
response = self.request.response
with open(path, 'rb') as f:
response.body = f.read()
os.remove(path)
response.content_length = len(response.body)
response.content_type = b'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
response.content_disposition = b'attachment; filename={}.xlsx'.format(self.get_grid_key())
return response
def get_xlsx_fields(self):
"""
Return the list of fields to be written to XLSX download.
"""
fields = []
mapper = orm.class_mapper(self.model_class)
for prop in mapper.iterate_properties:
if isinstance(prop, orm.ColumnProperty):
fields.append(prop.key)
return fields
def get_xlsx_row(self, obj, fields):
"""
Return a dict for use when writing the row's data to CSV download.
"""
row = {}
for field in fields:
row[field] = getattr(obj, field, None)
return row
def row_results_csv(self):
"""
Download current row results data for an object, as CSV
@ -1965,6 +2019,13 @@ class MasterView(View):
config.add_view(cls, attr='results_csv', route_name='{}.results_csv'.format(route_prefix),
permission='{}.results_csv'.format(permission_prefix))
if cls.results_downloadable_xlsx:
config.add_tailbone_permission(permission_prefix, '{}.results_xlsx'.format(permission_prefix),
"Download {} as XLSX".format(model_title_plural))
config.add_route('{}.results_xlsx'.format(route_prefix), '{}/xlsx'.format(url_prefix))
config.add_view(cls, attr='results_xlsx', route_name='{}.results_xlsx'.format(route_prefix),
permission='{}.results_xlsx'.format(permission_prefix))
# create
if cls.creatable or cls.mobile_creatable: