ConstructionConsultationSystem/xadmin/plugins/export.py

250 lines
9.3 KiB
Python
Raw Normal View History

2019-03-18 19:31:50 +08:00
import io
import datetime
import sys
from future.utils import iteritems
from django.http import HttpResponse
from django.template import loader
from django.utils import six
from django.utils.encoding import force_text, smart_text
from django.utils.html import escape
from django.utils.translation import ugettext as _
from django.utils.xmlutils import SimplerXMLGenerator
from django.db.models import BooleanField, NullBooleanField
from xadmin.plugins.utils import get_context_dict
from xadmin.sites import site
from xadmin.views import BaseAdminPlugin, ListAdminView
from xadmin.util import json
from xadmin.views.list import ALL_VAR
try:
import xlwt
has_xlwt = True
except:
has_xlwt = False
try:
import xlsxwriter
has_xlsxwriter = True
except:
has_xlsxwriter = False
class ExportMenuPlugin(BaseAdminPlugin):
list_export = ('xlsx', 'xls', 'csv', 'xml', 'json')
export_names = {'xlsx': 'Excel 2007', 'xls': 'Excel', 'csv': 'CSV',
'xml': 'XML', 'json': 'JSON'}
def init_request(self, *args, **kwargs):
self.list_export = [
f for f in self.list_export
if (f != 'xlsx' or has_xlsxwriter) and (f != 'xls' or has_xlwt)]
def block_top_toolbar(self, context, nodes):
if self.list_export:
context.update({
'show_export_all': self.admin_view.paginator.count > self.admin_view.list_per_page and not ALL_VAR in self.admin_view.request.GET,
'form_params': self.admin_view.get_form_params({'_do_': 'export'}, ('export_type',)),
'export_types': [{'type': et, 'name': self.export_names[et]} for et in self.list_export],
})
nodes.append(loader.render_to_string('xadmin/blocks/model_list.top_toolbar.exports.html',
context=get_context_dict(context)))
class ExportPlugin(BaseAdminPlugin):
export_mimes = {'xlsx': 'application/vnd.ms-excel',
'xls': 'application/vnd.ms-excel', 'csv': 'text/csv',
'xml': 'application/xhtml+xml', 'json': 'application/json'}
def init_request(self, *args, **kwargs):
return self.request.GET.get('_do_') == 'export'
def _format_value(self, o):
if (o.field is None and getattr(o.attr, 'boolean', False)) or \
(o.field and isinstance(o.field, (BooleanField, NullBooleanField))):
value = o.value
elif str(o.text).startswith("<span class='text-muted'>"):
value = escape(str(o.text)[25:-7])
else:
value = escape(str(o.text))
return value
def _get_objects(self, context):
headers = [c for c in context['result_headers'].cells if c.export]
rows = context['results']
return [dict([
(force_text(headers[i].text), self._format_value(o)) for i, o in
enumerate(filter(lambda c:getattr(c, 'export', False), r.cells))]) for r in rows]
def _get_datas(self, context):
rows = context['results']
new_rows = [[self._format_value(o) for o in
filter(lambda c:getattr(c, 'export', False), r.cells)] for r in rows]
new_rows.insert(0, [force_text(c.text) for c in context['result_headers'].cells if c.export])
return new_rows
def get_xlsx_export(self, context):
datas = self._get_datas(context)
output = io.BytesIO()
export_header = (
self.request.GET.get('export_xlsx_header', 'off') == 'on')
model_name = self.opts.verbose_name
book = xlsxwriter.Workbook(output)
sheet = book.add_worksheet(
u"%s %s" % (_(u'Sheet'), force_text(model_name)))
styles = {'datetime': book.add_format({'num_format': 'yyyy-mm-dd hh:mm:ss'}),
'date': book.add_format({'num_format': 'yyyy-mm-dd'}),
'time': book.add_format({'num_format': 'hh:mm:ss'}),
'header': book.add_format({'font': 'name Times New Roman', 'color': 'red', 'bold': 'on', 'num_format': '#,##0.00'}),
'default': book.add_format()}
if not export_header:
datas = datas[1:]
for rowx, row in enumerate(datas):
for colx, value in enumerate(row):
if export_header and rowx == 0:
cell_style = styles['header']
else:
if isinstance(value, datetime.datetime):
cell_style = styles['datetime']
elif isinstance(value, datetime.date):
cell_style = styles['date']
elif isinstance(value, datetime.time):
cell_style = styles['time']
else:
cell_style = styles['default']
sheet.write(rowx, colx, value, cell_style)
book.close()
output.seek(0)
return output.getvalue()
def get_xls_export(self, context):
datas = self._get_datas(context)
output = io.BytesIO()
export_header = (
self.request.GET.get('export_xls_header', 'off') == 'on')
model_name = self.opts.verbose_name
book = xlwt.Workbook(encoding='utf8')
sheet = book.add_sheet(
u"%s %s" % (_(u'Sheet'), force_text(model_name)))
styles = {'datetime': xlwt.easyxf(num_format_str='yyyy-mm-dd hh:mm:ss'),
'date': xlwt.easyxf(num_format_str='yyyy-mm-dd'),
'time': xlwt.easyxf(num_format_str='hh:mm:ss'),
'header': xlwt.easyxf('font: name Times New Roman, color-index red, bold on', num_format_str='#,##0.00'),
'default': xlwt.Style.default_style}
if not export_header:
datas = datas[1:]
for rowx, row in enumerate(datas):
for colx, value in enumerate(row):
if export_header and rowx == 0:
cell_style = styles['header']
else:
if isinstance(value, datetime.datetime):
cell_style = styles['datetime']
elif isinstance(value, datetime.date):
cell_style = styles['date']
elif isinstance(value, datetime.time):
cell_style = styles['time']
else:
cell_style = styles['default']
sheet.write(rowx, colx, value, style=cell_style)
book.save(output)
output.seek(0)
return output.getvalue()
def _format_csv_text(self, t):
if isinstance(t, bool):
return _('Yes') if t else _('No')
t = t.replace('"', '""').replace(',', '\,')
cls_str = str if six.PY3 else basestring
if isinstance(t, cls_str):
t = '"%s"' % t
return t
def get_csv_export(self, context):
datas = self._get_datas(context)
stream = []
if self.request.GET.get('export_csv_header', 'off') != 'on':
datas = datas[1:]
for row in datas:
stream.append(','.join(map(self._format_csv_text, row)))
return '\r\n'.join(stream)
def _to_xml(self, xml, data):
if isinstance(data, (list, tuple)):
for item in data:
xml.startElement("row", {})
self._to_xml(xml, item)
xml.endElement("row")
elif isinstance(data, dict):
for key, value in iteritems(data):
key = key.replace(' ', '_')
xml.startElement(key, {})
self._to_xml(xml, value)
xml.endElement(key)
else:
xml.characters(smart_text(data))
def get_xml_export(self, context):
results = self._get_objects(context)
stream = io.StringIO()
xml = SimplerXMLGenerator(stream, "utf-8")
xml.startDocument()
xml.startElement("objects", {})
self._to_xml(xml, results)
xml.endElement("objects")
xml.endDocument()
return stream.getvalue().split('\n')[1]
def get_json_export(self, context):
results = self._get_objects(context)
return json.dumps({'objects': results}, ensure_ascii=False,
indent=(self.request.GET.get('export_json_format', 'off') == 'on') and 4 or None)
def get_response(self, response, context, *args, **kwargs):
file_type = self.request.GET.get('export_type', 'csv')
response = HttpResponse(
content_type="%s; charset=UTF-8" % self.export_mimes[file_type])
file_name = self.opts.verbose_name.replace(' ', '_')
response['Content-Disposition'] = ('attachment; filename=%s.%s' % (
file_name, file_type)).encode('utf-8')
response.write(getattr(self, 'get_%s_export' % file_type)(context))
return response
# View Methods
def get_result_list(self, __):
if self.request.GET.get('all', 'off') == 'on':
self.admin_view.list_per_page = sys.maxsize
return __()
def result_header(self, item, field_name, row):
item.export = not item.attr or field_name == '__str__' or getattr(item.attr, 'allow_export', True)
return item
def result_item(self, item, obj, field_name, row):
item.export = item.field or field_name == '__str__' or getattr(item.attr, 'allow_export', True)
return item
site.register_plugin(ExportMenuPlugin, ListAdminView)
site.register_plugin(ExportPlugin, ListAdminView)