better export in grid, thanks Niphlod
This commit is contained in:
@@ -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
@@ -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')
|
||||||
|
|||||||
Reference in New Issue
Block a user