better export in grid, thanks Niphlod

This commit is contained in:
mdipierro
2012-07-19 16:25:22 -05:00
parent f1337d563e
commit f01b61c4c9
2 changed files with 135 additions and 59 deletions
+1 -1
View File
@@ -1 +1 @@
Version 2.00.0 (2012-07-18 21:46:56) dev Version 2.00.0 (2012-07-19 16:25:16) dev
+134 -58
View File
@@ -13,13 +13,17 @@ Holds:
- form_factory: provides a SQLFORM for an non-db backed table - form_factory: provides a SQLFORM for an non-db backed table
""" """
try:
from urlparse import parse_qs as psq
except ImportError:
from cgi import parse_qs as psq
from http import HTTP from http import HTTP
from html import XML, SPAN, TAG, A, DIV, CAT, UL, LI, TEXTAREA, BR from html import XML, SPAN, TAG, A, DIV, CAT, UL, LI, TEXTAREA, BR, IMG, SCRIPT
from html import FORM, INPUT, LABEL, OPTION, SELECT, BUTTON, IMG from html import FORM, INPUT, LABEL, OPTION, SELECT, BUTTON
from html import TABLE, THEAD, TBODY, TR, TD, TH, STYLE, SCRIPT from html import TABLE, THEAD, TBODY, TR, TD, TH, STYLE
from html import URL, truncate_string from html import URL, truncate_string
from dal import DAL, Field, Table, Row, CALLABLETYPES, smart_query from dal import DAL, Field, Table, Row, CALLABLETYPES, smart_query, \
bar_encode, regex_table_field, Reference
from storage import Storage from storage import Storage
from utils import md5_hash from utils import md5_hash
from validators import IS_EMPTY_OR, IS_NOT_EMPTY, IS_LIST_OF, IS_DATE, \ from validators import IS_EMPTY_OR, IS_NOT_EMPTY, IS_LIST_OF, IS_DATE, \
@@ -1694,32 +1698,34 @@ class SQLFORM(FORM):
ondelete(table,request.args[-1]) ondelete(table,request.args[-1])
ret = db(table[table._id.name]==request.args[-1]).delete() ret = db(table[table._id.name]==request.args[-1]).delete()
return ret return ret
elif csv and len(request.args)>0 and request.args[-1]=='csv':
if request.vars.keywords: #elif csv and len(request.args)>0 and request.args[-1]=='csv':
try: # if request.vars.keywords:
dbset=dbset(SQLFORM.build_query( # try:
fields, # dbset=dbset(SQLFORM.build_query(
request.vars.get('keywords',''))) # fields,
except: # request.vars.get('keywords','')))
raise HTTP(400) # except:
check_authorization() # raise HTTP(400)
response.headers['Content-Type'] = 'text/csv' # check_authorization()
response.headers['Content-Disposition'] = \ # response.headers['Content-Type'] = 'text/csv'
'attachment;filename=rows.csv;' # response.headers['Content-Disposition'] = \
raise HTTP(200,str(dbset.select()), # 'attachment;filename=rows.csv;'
**{'Content-Type':'text/csv', # raise HTTP(200,str(dbset.select()),
'Content-Disposition':'attachment;filename=rows.csv;'}) # **{'Content-Type':'text/csv',
# 'Content-Disposition':'attachment;filename=rows.csv;'})
#============================================================================== #==============================================================================
exportManager = dict(csv_with_hidden_cols=(ExporterCsv,'csv with hidden cols'), exportManager = dict(csv_with_hidden_cols=(ExporterCsv,'csv, hidden cols'),
csv=ExporterCsv, csv=ExporterCsv,
html=ExporterHtml, html=ExporterHtml,
tsv_with_hidden_cols=(ExporterTsv, 'tsv with hidden cols'), tsv_with_hidden_cols=(ExporterTsv, 'tsv (Excel compatible), hidden cols'),
tsv=ExporterTsv) tsv=(ExporterTsv, 'tsv (Excel compatible)')
)
if not exportclasses is None: if not exportclasses is None:
exportManager.update(exportclasses) exportManager.update(exportclasses)
if len(request.args)>0 and request.args[-1]=='export': if len(request.args)>0 and request.args[-1]=='export':
export_type = request.vars.export_type export_type = request.vars.export_type
order = request.vars.order or '' order = request.vars.order or ''
@@ -1734,7 +1740,7 @@ class SQLFORM(FORM):
orderby=~db[tablename][fieldname] orderby=~db[tablename][fieldname]
else: else:
orderby=db[tablename][fieldname] orderby=db[tablename][fieldname]
table_fields = [f for f in fields if f._tablename in tablenames] table_fields = [f for f in fields if f._tablename in tablenames]
if export_type in ('csv_with_hidden_cols','tsv_with_hidden_cols'): if export_type in ('csv_with_hidden_cols','tsv_with_hidden_cols'):
if request.vars.keywords: if request.vars.keywords:
@@ -1744,11 +1750,15 @@ class SQLFORM(FORM):
request.vars.get('keywords',''))) request.vars.get('keywords','')))
except: except:
raise HTTP(400) raise HTTP(400)
check_authorization()
rows = dbset.select() rows = dbset.select()
else: else:
rows = dbset.select(left=left,orderby=orderby,*columns) rows = dbset.select(left=left,orderby=orderby,*columns)
##FIXME ?
#check_authorization()
if user_signature:
if not URL.verify(request,user_signature=user_signature,hash_vars=False):
session.flash = T('not authorized')
redirect(referrer)
if not export_type is None: if not export_type is None:
if exportManager.has_key(export_type): if exportManager.has_key(export_type):
value = exportManager[export_type] value = exportManager[export_type]
@@ -1761,12 +1771,12 @@ class SQLFORM(FORM):
response.headers['Content-Type'] = oExp.content_type response.headers['Content-Type'] = oExp.content_type
response.headers['Content-Disposition'] = \ response.headers['Content-Disposition'] = \
'attachment;filename='+filename+';' 'attachment;filename='+filename+';'
raise HTTP(200, oExp.export(), raise HTTP(200, oExp.export(),
**{'Content-Type':oExp.content_type, **{'Content-Type':oExp.content_type,
'Content-Disposition':'attachment;filename='+filename+';'}) 'Content-Disposition':'attachment;filename='+filename+';'})
#================================================================================ #================================================================================
elif request.vars.records and not isinstance( elif request.vars.records and not isinstance(
request.vars.records,list): request.vars.records,list):
request.vars.records=[request.vars.records] request.vars.records=[request.vars.records]
@@ -1792,7 +1802,7 @@ class SQLFORM(FORM):
INPUT(_type='submit',_value=T('Search')), INPUT(_type='submit',_value=T('Search')),
INPUT(_type='submit',_value=T('Clear'), INPUT(_type='submit',_value=T('Clear'),
_onclick="jQuery('#web2py_keywords').val('');"), _onclick="jQuery('#web2py_keywords').val('');"),
mf,ms,_method="GET",_action=url) mf,ms,_method="GET",_action=url)
form = search_widget and search_widget(sfields,url()) or '' form = search_widget and search_widget(sfields,url()) or ''
console.append(form) console.append(form)
keywords = request.vars.get('keywords','') keywords = request.vars.get('keywords','')
@@ -1825,13 +1835,13 @@ class SQLFORM(FORM):
buttontext='Add', buttontext='Add',
buttonurl=url(args=['new',tablename]))) buttonurl=url(args=['new',tablename])))
if csv and nrows: if csv and nrows:
search_actions.append(gridbutton( #search_actions.append(gridbutton(
buttonclass='buttonexport', # buttonclass='buttonexport',
buttontext='Export', # buttontext='Export',
trap = False, # trap = False,
buttonurl=url(args=['csv'], # buttonurl=url(args=['csv'],
vars=dict(keywords=request.vars.keywords or '')))) # vars=dict(keywords=request.vars.keywords or ''))))
#================================================================ #================================================================
options =[] options =[]
for k,v in sorted(exportManager.items()): for k,v in sorted(exportManager.items()):
@@ -1840,11 +1850,16 @@ class SQLFORM(FORM):
else: else:
label = k label = k
options.append(OPTION(T(label),_value=k)) options.append(OPTION(T(label),_value=k))
f = FORM(BUTTON(SPAN(_class="icon downarrow icon-download"), ##FIXME ?
"Export", _type="submit", _class="btn button"), mysignature = url(args=['export']).split('?', 1)
SELECT(options, _name="export_type"), mysignature = psq(mysignature[-1]).get('_signature', [None])[-1]
f = FORM(BUTTON(SPAN(_class=ui.get('buttonexport')),
"Export", _type="submit", _class=ui.get('button')),
SELECT(options, _name="export_type"),
INPUT(_type="hidden", _name="order", INPUT(_type="hidden", _name="order",
_value=request.vars.order), _value=request.vars.order),
INPUT(_type="hidden", _name="_signature",
_value=mysignature),
INPUT(_type="hidden", _name="keywords", INPUT(_type="hidden", _name="keywords",
_value=request.vars.keywords or ''), _value=request.vars.keywords or ''),
_method="GET", _action=url(args=['export'])) _method="GET", _action=url(args=['export']))
@@ -2148,21 +2163,21 @@ class SQLFORM(FORM):
check = {} check = {}
id_field_name = table._id.name id_field_name = table._id.name
for tablename,fieldname in table._referenced_by: for tablename,fieldname in table._referenced_by:
if db[tablename][fieldname].readable: if db[tablename][fieldname].readable:
check[tablename] = check.get(tablename,[])+[fieldname] check[tablename] = check.get(tablename,[])+[fieldname]
for tablename in sorted(check): for tablename in sorted(check):
linked_fieldnames = check[tablename] linked_fieldnames = check[tablename]
tb = db[tablename] tb = db[tablename]
multiple_links = len(linked_fieldnames)>1 multiple_links = len(linked_fieldnames)>1
for fieldname in linked_fieldnames: for fieldname in linked_fieldnames:
if linked_tables is None or tablename in linked_tables: if linked_tables is None or tablename in linked_tables:
t = T(tb._plural) if not multiple_links else T(tb._plural+'('+fieldname+')') t = T(tb._plural) if not multiple_links else T(tb._plural+'('+fieldname+')')
args0 = tablename+'.'+fieldname args0 = tablename+'.'+fieldname
links.append( links.append(
lambda row,t=t,nargs=nargs,args0=args0:\ lambda row,t=t,nargs=nargs,args0=args0:\
A(SPAN(t),_class=trap_class(),_href=URL( A(SPAN(t),_class=trap_class(),_href=URL(
args=request.args[:nargs]+[args0,row[id_field_name]]))) args=request.args[:nargs]+[args0,row[id_field_name]])))
grid=SQLFORM.grid(query,args=request.args[:nargs],links=links, grid=SQLFORM.grid(query,args=request.args[:nargs],links=links,
links_in_grid=links_in_grid, links_in_grid=links_in_grid,
user_signature=user_signature,**kwargs) user_signature=user_signature,**kwargs)
@@ -2461,43 +2476,104 @@ form_factory = SQLFORM.factory # for backward compatibility, deprecated
class ExportClass(object): class ExportClass(object):
file_ext = None file_ext = None
content_type = None content_type = None
def __init__(self, rows): def __init__(self, rows):
self.rows = rows self.rows = rows
def represented(self):
def none_exception(value):
"""
returns a cleaned up value that can be used for csv export:
- unicode text is encoded as such
- None values are replaced with the given representation (default <NULL>)
"""
if value is None:
return '<NULL>'
elif isinstance(value, unicode):
return value.encode('utf8')
elif isinstance(value,Reference):
return int(value)
elif hasattr(value, 'isoformat'):
return value.isoformat()[:19].replace('T', ' ')
elif isinstance(value, (list,tuple)): # for type='list:..'
return bar_encode(value)
return value
represented = []
for record in self.rows:
row = []
for col in self.rows.colnames:
if not regex_table_field.match(col):
row.append(record._extra[col])
else:
(t, f) = col.split('.')
field = self.rows.db[t][f]
if isinstance(record.get(t, None), (Row,dict)):
value = record[t][f]
else:
value = record[f]
if field.type=='blob' and not value is None:
value = ''
elif field.represent:
value = field.represent(value, record)
row.append(none_exception(value))
represented.append(row)
return represented
def export(self): def export(self):
raise NotImplementedError raise NotImplementedError
class ExporterTsv(ExportClass): class ExporterTsv(ExportClass):
file_ext = "tsv"
file_ext = "csv"
content_type = "text/tab-separated-values" content_type = "text/tab-separated-values"
def __init__(self, rows): def __init__(self, rows):
ExportClass.__init__(self, rows) ExportClass.__init__(self, rows)
def export(self): def export(self):
out = cStringIO.StringIO() out = cStringIO.StringIO()
self.rows.export_to_csv_file(out, delimiter='\t', represent=True) final = cStringIO.StringIO()
return str(out.getvalue()) import csv
writer = csv.writer(out, delimiter='\t')
import codecs
final.write(codecs.BOM_UTF16)
colnames = [a.split('.') for a in self.rows.colnames]
writer.writerow([unicode(col).encode("utf8") for col in self.rows.colnames])
data = out.getvalue().decode("utf8")
data = data.encode("utf-16")
data = data[2:]
final.write(data)
out.truncate(0)
records = self.represented()
for row in records:
writer.writerow([str(col).decode('utf8').encode("utf-8") for col in row])
data = out.getvalue().decode("utf8")
data = data.encode("utf-16")
data = data[2:]
final.write(data)
out.truncate(0)
return str(final.getvalue())
class ExporterCsv(ExportClass): class ExporterCsv(ExportClass):
file_ext = "csv" file_ext = "csv"
content_type = "text/csv" content_type = "text/csv"
def __init__(self, rows): def __init__(self, rows):
ExportClass.__init__(self, rows) ExportClass.__init__(self, rows)
def export(self): def export(self):
return str(self.rows) return str(self.rows)
class ExporterHtml(ExportClass): class ExporterHtml(ExportClass):
file_ext = "html" file_ext = "html"
content_type = "text/html" content_type = "text/html"
def __init__(self, rows): def __init__(self, rows):
ExportClass.__init__(self, rows) ExportClass.__init__(self, rows)
def export(self): def export(self):
out = cStringIO.StringIO() out = cStringIO.StringIO()
out.write('<html>\n<body>\n<table>\n') out.write('<html>\n<body>\n<table>\n')