Add ability to download batch row data as CSV.

This commit is contained in:
Lance Edgar 2015-08-19 20:06:13 -05:00
parent 6c5eec7981
commit 73939b825e
3 changed files with 78 additions and 12 deletions

View file

@ -42,9 +42,7 @@
</style>
</%def>
<div class="form-wrapper">
<ul class="context-menu">
<%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:
@ -57,6 +55,12 @@
% 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">
<ul class="context-menu">
${self.context_menu_items()}
</ul>
${form.render(form_id='batch-form', buttons=capture(buttons))|n}

View file

@ -13,6 +13,13 @@
</script>
</%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()">
<div class="buttons">
% if not form.readonly and batch.refreshable:

View file

@ -32,6 +32,9 @@ from __future__ import unicode_literals
import os
import datetime
import logging
from cStringIO import StringIO
from sqlalchemy import orm
import formalchemy
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 Session as RatSession
from rattail.threads import Thread
from rattail.csvutil import UnicodeDictWriter
from tailbone.db import Session
from tailbone.views import SearchableAlchemyGridView, CrudView
@ -366,6 +370,10 @@ class BatchCrud(BaseCrud):
def batch_class(self):
raise NotImplementedError
@property
def batch_row_class(self):
raise NotImplementedError
@property
def mapped_class(self):
return self.batch_class
@ -705,6 +713,48 @@ class BatchCrud(BaseCrud):
progress.session['success_url'] = self.view_url(batch.uuid)
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):
"""
@ -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),
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
if hasattr(batch_crud, 'download'):
config.add_route('{0}.download'.format(route_prefix), '{0}{{uuid}}/download'.format(url_prefix))