Commit a8e8a535 authored by Iuri de Silvio's avatar Iuri de Silvio

Tablib export.

parent baf191d1
import warnings import warnings
import re import re
import csv import csv
import mimetypes
import time import time
from werkzeug import secure_filename from werkzeug import secure_filename
...@@ -8,6 +9,10 @@ from werkzeug import secure_filename ...@@ -8,6 +9,10 @@ from werkzeug import secure_filename
from flask import (request, redirect, flash, abort, json, Response, from flask import (request, redirect, flash, abort, json, Response,
get_flashed_messages, stream_with_context) get_flashed_messages, stream_with_context)
from jinja2 import contextfunction from jinja2 import contextfunction
try:
import tablib
except ImportError:
tablib = None
from wtforms.fields import HiddenField from wtforms.fields import HiddenField
from wtforms.fields.core import UnboundField from wtforms.fields.core import UnboundField
from wtforms.validators import ValidationError, InputRequired from wtforms.validators import ValidationError, InputRequired
...@@ -683,6 +688,15 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -683,6 +688,15 @@ class BaseModelView(BaseView, ActionsMixin):
Unlimited by default. Uses `page_size` if set to `None`. Unlimited by default. Uses `page_size` if set to `None`.
""" """
export_type = 'csv'
"""
Export type, `csv` as default and can be changed to any tablib
supported type.
Check tablib for https://github.com/kennethreitz/tablib/bloab/master/README.rst
for supported types.
"""
# Various settings # Various settings
page_size = 20 page_size = 20
""" """
...@@ -1696,12 +1710,13 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -1696,12 +1710,13 @@ class BaseModelView(BaseView, ActionsMixin):
self.column_type_formatters_export, self.column_type_formatters_export,
) )
def get_export_name(self): def get_export_name(self, export_type='csv'):
""" """
:return: The exported csv file name. :return: The exported csv file name.
""" """
filename = '%s_%s.csv' % (self.name, filename = '%s_%s.%s' % (self.name,
time.strftime("%Y-%m-%d_%H-%M-%S")) time.strftime("%Y-%m-%d_%H-%M-%S"),
export_type)
return filename return filename
# AJAX references # AJAX references
...@@ -2001,17 +2016,7 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -2001,17 +2016,7 @@ class BaseModelView(BaseView, ActionsMixin):
""" """
return self.handle_action() return self.handle_action()
@expose('/export/csv/') def _export_data(self):
def export_csv(self):
"""
Export a CSV of records.
"""
return_url = get_redirect_target() or self.get_url('.index_view')
if not self.can_export:
flash(gettext('Permission denied.'))
return redirect(return_url)
# Macros in column_formatters are not supported. # Macros in column_formatters are not supported.
# Macros will have a function name 'inner' # Macros will have a function name 'inner'
# This causes non-macro functions named 'inner' not work. # This causes non-macro functions named 'inner' not work.
...@@ -2040,6 +2045,28 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -2040,6 +2045,28 @@ class BaseModelView(BaseView, ActionsMixin):
view_args.search, view_args.filters, view_args.search, view_args.filters,
page_size=self.export_max_rows) page_size=self.export_max_rows)
return count, data
@expose('/export/<export_type>/')
def export(self, export_type):
if export_type == 'csv':
return self.export_csv()
else:
return self._export_tablib(export_type)
@expose('/export/csv/')
def export_csv(self):
"""
Export a CSV of records.
"""
return_url = get_redirect_target() or self.get_url('.index_view')
if not self.can_export:
flash(gettext('Permission denied.'))
return redirect(return_url)
count, data = self._export_data()
# https://docs.djangoproject.com/en/1.8/howto/outputting-csv/ # https://docs.djangoproject.com/en/1.8/howto/outputting-csv/
class Echo(object): class Echo(object):
""" """
...@@ -2065,7 +2092,7 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -2065,7 +2092,7 @@ class BaseModelView(BaseView, ActionsMixin):
for c in self._export_columns] for c in self._export_columns]
yield writer.writerow(vals) yield writer.writerow(vals)
filename = self.get_export_name() filename = self.get_export_name(export_type='csv')
disposition = 'attachment;filename=%s' % (secure_filename(filename),) disposition = 'attachment;filename=%s' % (secure_filename(filename),)
...@@ -2075,6 +2102,51 @@ class BaseModelView(BaseView, ActionsMixin): ...@@ -2075,6 +2102,51 @@ class BaseModelView(BaseView, ActionsMixin):
mimetype='text/csv' mimetype='text/csv'
) )
def _export_tablib(self, export_type):
return_url = get_redirect_target() or self.get_url('.index_view')
if tablib is None:
flash(gettext('Tablib dependency not installed.'))
return redirect(return_url)
if not self.can_export:
flash(gettext('Permission denied.'))
return redirect(return_url)
filename = self.get_export_name(export_type)
disposition = 'attachment;filename=%s' % (secure_filename(filename),)
mimetype, encoding = mimetypes.guess_type(filename)
if not mimetype:
mimetype = 'application/octet-stream'
if encoding:
mimetype = '%s; charset=%s' % (mimetype, encoding)
ds = tablib.Dataset(headers=[c[1] for c in self._export_columns])
count, data = self._export_data()
for row in data:
vals = [self.get_export_value(row, c[0]) for c in self._export_columns]
ds.append(vals)
try:
try:
response_data = ds.export(format=export_type)
except AttributeError:
response_data = getattr(ds, export_type)
except (AttributeError, tablib.UnsupportedFormat):
flash(gettext('Export type "%(type)s not supported.',
type=export_type))
return redirect(return_url)
return Response(
response_data,
headers={'Content-Disposition': disposition},
mimetype=mimetype,
)
@expose('/ajax/lookup/') @expose('/ajax/lookup/')
def ajax_lookup(self): def ajax_lookup(self):
name = request.args.get('name') name = request.args.get('name')
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
{% if admin_view.can_export %} {% if admin_view.can_export %}
<li> <li>
<a href="{{ get_url('.export_csv', **request.args) }}" title="{{ _gettext('Export') }}">{{ _gettext('Export') }}</a> <a href="{{ get_url('.export', export_type=admin_view.export_type, **request.args) }}" title="{{ _gettext('Export') }}">{{ _gettext('Export') }}</a>
</li> </li>
{% endif %} {% endif %}
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
{% if admin_view.can_export %} {% if admin_view.can_export %}
<li> <li>
<a href="{{ get_url('.export_csv', **request.args) }}" title="{{ _gettext('Export') }}">{{ _gettext('Export') }}</a> <a href="{{ get_url('.export', export_type=admin_view.export_type, **request.args) }}" title="{{ _gettext('Export') }}">{{ _gettext('Export') }}</a>
</li> </li>
{% endif %} {% endif %}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment