Add ability to download batch row data as CSV.
This commit is contained in:
parent
6c5eec7981
commit
73939b825e
|
@ -42,21 +42,25 @@
|
||||||
</style>
|
</style>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
<li>${h.link_to("Back to {0}".format(batch_display_plural), url(route_prefix))}</li>
|
||||||
|
% if not batch.executed:
|
||||||
|
% if form.updating:
|
||||||
|
<li>${h.link_to("View this {0}".format(batch_display), url('{0}.view'.format(route_prefix), uuid=batch.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
% if form.readonly and request.has_perm('{0}.edit'.format(permission_prefix)):
|
||||||
|
<li>${h.link_to("Edit this {0}".format(batch_display), url('{0}.edit'.format(route_prefix), uuid=batch.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
% endif
|
||||||
|
% if request.has_perm('{0}.delete'.format(permission_prefix)):
|
||||||
|
<li>${h.link_to("Delete this {0}".format(batch_display), url('{0}.delete'.format(route_prefix), uuid=batch.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
<div class="form-wrapper">
|
<div class="form-wrapper">
|
||||||
|
|
||||||
<ul class="context-menu">
|
<ul class="context-menu">
|
||||||
<li>${h.link_to("Back to {0}".format(batch_display_plural), url(route_prefix))}</li>
|
${self.context_menu_items()}
|
||||||
% if not batch.executed:
|
|
||||||
% if form.updating:
|
|
||||||
<li>${h.link_to("View this {0}".format(batch_display), url('{0}.view'.format(route_prefix), uuid=batch.uuid))}</li>
|
|
||||||
% endif
|
|
||||||
% if form.readonly and request.has_perm('{0}.edit'.format(permission_prefix)):
|
|
||||||
<li>${h.link_to("Edit this {0}".format(batch_display), url('{0}.edit'.format(route_prefix), uuid=batch.uuid))}</li>
|
|
||||||
% endif
|
|
||||||
% endif
|
|
||||||
% if request.has_perm('{0}.delete'.format(permission_prefix)):
|
|
||||||
<li>${h.link_to("Delete this {0}".format(batch_display), url('{0}.delete'.format(route_prefix), uuid=batch.uuid))}</li>
|
|
||||||
% endif
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
${form.render(form_id='batch-form', buttons=capture(buttons))|n}
|
${form.render(form_id='batch-form', buttons=capture(buttons))|n}
|
||||||
|
|
|
@ -13,6 +13,13 @@
|
||||||
</script>
|
</script>
|
||||||
</%def>
|
</%def>
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
${parent.context_menu_items()}
|
||||||
|
% if request.has_perm('{0}.csv'.format(permission_prefix)):
|
||||||
|
<li>${h.link_to("Download this {0} as CSV".format(batch_display), url('{0}.csv'.format(route_prefix), uuid=batch.uuid))}</li>
|
||||||
|
% endif
|
||||||
|
</%def>
|
||||||
|
|
||||||
<%def name="buttons()">
|
<%def name="buttons()">
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
% if not form.readonly and batch.refreshable:
|
% if not form.readonly and batch.refreshable:
|
||||||
|
|
|
@ -32,6 +32,9 @@ from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
|
from cStringIO import StringIO
|
||||||
|
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
import formalchemy
|
import formalchemy
|
||||||
from pyramid.renderers import render_to_response
|
from pyramid.renderers import render_to_response
|
||||||
|
@ -42,6 +45,7 @@ from webhelpers.html.tags import link_to, HTML
|
||||||
from rattail.db import model
|
from rattail.db import model
|
||||||
from rattail.db import Session as RatSession
|
from rattail.db import Session as RatSession
|
||||||
from rattail.threads import Thread
|
from rattail.threads import Thread
|
||||||
|
from rattail.csvutil import UnicodeDictWriter
|
||||||
|
|
||||||
from tailbone.db import Session
|
from tailbone.db import Session
|
||||||
from tailbone.views import SearchableAlchemyGridView, CrudView
|
from tailbone.views import SearchableAlchemyGridView, CrudView
|
||||||
|
@ -366,6 +370,10 @@ class BatchCrud(BaseCrud):
|
||||||
def batch_class(self):
|
def batch_class(self):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@property
|
||||||
|
def batch_row_class(self):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def mapped_class(self):
|
def mapped_class(self):
|
||||||
return self.batch_class
|
return self.batch_class
|
||||||
|
@ -705,6 +713,48 @@ class BatchCrud(BaseCrud):
|
||||||
progress.session['success_url'] = self.view_url(batch.uuid)
|
progress.session['success_url'] = self.view_url(batch.uuid)
|
||||||
progress.session.save()
|
progress.session.save()
|
||||||
|
|
||||||
|
def csv(self):
|
||||||
|
"""
|
||||||
|
Download batch data as CSV.
|
||||||
|
"""
|
||||||
|
batch = self.current_batch()
|
||||||
|
fields = self.get_csv_fields()
|
||||||
|
data = StringIO()
|
||||||
|
writer = UnicodeDictWriter(data, fields)
|
||||||
|
writer.writeheader()
|
||||||
|
for row in batch.data_rows:
|
||||||
|
if not row.removed:
|
||||||
|
writer.writerow(self.get_csv_row(row, fields))
|
||||||
|
response = self.request.response
|
||||||
|
response.text = data.getvalue().decode('utf_8')
|
||||||
|
data.close()
|
||||||
|
response.content_length = len(response.text)
|
||||||
|
response.content_type = b'text/csv'
|
||||||
|
response.content_disposition = b'attachment; filename=batch.csv'
|
||||||
|
return response
|
||||||
|
|
||||||
|
def get_csv_fields(self):
|
||||||
|
"""
|
||||||
|
Return the list of fields to be written to CSV download.
|
||||||
|
"""
|
||||||
|
fields = []
|
||||||
|
mapper = orm.class_mapper(self.batch_row_class)
|
||||||
|
for prop in mapper.iterate_properties:
|
||||||
|
if isinstance(prop, orm.ColumnProperty):
|
||||||
|
if prop.key != 'removed' and not prop.key.endswith('uuid'):
|
||||||
|
fields.append(prop.key)
|
||||||
|
return fields
|
||||||
|
|
||||||
|
def get_csv_row(self, row, fields):
|
||||||
|
"""
|
||||||
|
Return a dict for use when writing the row's data to CSV download.
|
||||||
|
"""
|
||||||
|
csvrow = {}
|
||||||
|
for field in fields:
|
||||||
|
value = getattr(row, field)
|
||||||
|
csvrow[field] = '' if value is None else unicode(value)
|
||||||
|
return csvrow
|
||||||
|
|
||||||
|
|
||||||
class FileBatchCrud(BatchCrud):
|
class FileBatchCrud(BatchCrud):
|
||||||
"""
|
"""
|
||||||
|
@ -1163,6 +1213,11 @@ def defaults(config, batch_grid, batch_crud, row_grid, row_crud, url_prefix,
|
||||||
config.add_view(batch_crud, attr='execute', route_name='{0}.execute'.format(route_prefix),
|
config.add_view(batch_crud, attr='execute', route_name='{0}.execute'.format(route_prefix),
|
||||||
permission='{0}.execute'.format(permission_prefix))
|
permission='{0}.execute'.format(permission_prefix))
|
||||||
|
|
||||||
|
# Download batch row data as CSV
|
||||||
|
config.add_route('{0}.csv'.format(route_prefix), '{0}{{uuid}}/csv'.format(url_prefix))
|
||||||
|
config.add_view(batch_crud, attr='csv', route_name='{0}.csv'.format(route_prefix),
|
||||||
|
permission='{0}.csv'.format(permission_prefix))
|
||||||
|
|
||||||
# Download batch data file
|
# Download batch data file
|
||||||
if hasattr(batch_crud, 'download'):
|
if hasattr(batch_crud, 'download'):
|
||||||
config.add_route('{0}.download'.format(route_prefix), '{0}{{uuid}}/download'.format(url_prefix))
|
config.add_route('{0}.download'.format(route_prefix), '{0}{{uuid}}/download'.format(url_prefix))
|
||||||
|
|
Loading…
Reference in a new issue