Add generic "download results as XLSX" feature
This commit is contained in:
parent
eaad87c704
commit
e5c5a071f2
|
@ -72,6 +72,9 @@
|
||||||
% if master.results_downloadable_csv and request.has_perm('{}.results_csv'.format(permission_prefix)):
|
% 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>
|
<li>${h.link_to("Download results as CSV", url('{}.results_csv'.format(route_prefix)))}</li>
|
||||||
% endif
|
% 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.creatable and request.has_perm('{}.create'.format(permission_prefix)):
|
||||||
% if master.creates_multiple:
|
% if master.creates_multiple:
|
||||||
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
|
<li>${h.link_to("Create new {}".format(model_title_plural), url('{}.create'.format(route_prefix)))}</li>
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
#
|
#
|
||||||
# Rattail -- Retail Software Framework
|
# Rattail -- Retail Software Framework
|
||||||
# Copyright © 2010-2017 Lance Edgar
|
# Copyright © 2010-2018 Lance Edgar
|
||||||
#
|
#
|
||||||
# This file is part of Rattail.
|
# This file is part of Rattail.
|
||||||
#
|
#
|
||||||
|
@ -41,6 +41,8 @@ from rattail.util import prettify
|
||||||
from rattail.time import localtime #, make_utc
|
from rattail.time import localtime #, make_utc
|
||||||
from rattail.threads import Thread
|
from rattail.threads import Thread
|
||||||
from rattail.csvutil import UnicodeDictWriter
|
from rattail.csvutil import UnicodeDictWriter
|
||||||
|
from rattail.files import temp_path
|
||||||
|
from rattail.excel import ExcelWriter
|
||||||
|
|
||||||
import formalchemy as fa
|
import formalchemy as fa
|
||||||
from pyramid import httpexceptions
|
from pyramid import httpexceptions
|
||||||
|
@ -66,6 +68,7 @@ class MasterView(View):
|
||||||
|
|
||||||
listable = True
|
listable = True
|
||||||
results_downloadable_csv = False
|
results_downloadable_csv = False
|
||||||
|
results_downloadable_xlsx = False
|
||||||
creatable = True
|
creatable = True
|
||||||
viewable = True
|
viewable = True
|
||||||
editable = True
|
editable = True
|
||||||
|
@ -1472,6 +1475,57 @@ class MasterView(View):
|
||||||
response.content_disposition = b'attachment; filename={}.csv'.format(self.get_grid_key())
|
response.content_disposition = b'attachment; filename={}.csv'.format(self.get_grid_key())
|
||||||
return response
|
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):
|
def row_results_csv(self):
|
||||||
"""
|
"""
|
||||||
Download current row results data for an object, as CSV
|
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),
|
config.add_view(cls, attr='results_csv', route_name='{}.results_csv'.format(route_prefix),
|
||||||
permission='{}.results_csv'.format(permission_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
|
# create
|
||||||
if cls.creatable or cls.mobile_creatable:
|
if cls.creatable or cls.mobile_creatable:
|
||||||
|
|
Loading…
Reference in a new issue