diff --git a/gluon/sqlhtml.py b/gluon/sqlhtml.py index 73600ef5..9f5f62d7 100644 --- a/gluon/sqlhtml.py +++ b/gluon/sqlhtml.py @@ -41,13 +41,15 @@ try: import gluon.settings as settings is_gae = settings.global_settings.web2py_runtime_gae except ImportError: - is_gae = False # this is an assumption (if settings missing) + is_gae = False # this is an assumption (if settings missing) widget_class = re.compile('^\w*') -def add_class(a,b): + +def add_class(a, b): return a+' '+b if a else b + def represent(field, value, record): f = field.represent if not callable(f): @@ -83,18 +85,18 @@ def show_if(cond): base = "%s_%s" % (cond.first.tablename, cond.first.name) if ((cond.op.__name__ == 'EQ' and cond.second == True) or (cond.op.__name__ == 'NE' and cond.second == False)): - return base,":checked" + return base, ":checked" if ((cond.op.__name__ == 'EQ' and cond.second == False) or (cond.op.__name__ == 'NE' and cond.second == True)): - return base,":not(:checked)" + return base, ":not(:checked)" if cond.op.__name__ == 'EQ': - return base,"[value='%s']" % cond.second + return base, "[value='%s']" % cond.second if cond.op.__name__ == 'NE': - return base,"[value!='%s']" % cond.second + return base, "[value!='%s']" % cond.second if cond.op.__name__ == 'CONTAINS': - return base,"[value~='%s']" % cond.second - if cond.op.__name__ == 'BELONGS' and isinstance(cond.second,(list,tuple)): - return base,','.join("[value='%s']" % (v) for v in cond.second) + return base, "[value~='%s']" % cond.second + if cond.op.__name__ == 'BELONGS' and isinstance(cond.second, (list, tuple)): + return base, ','.join("[value='%s']" % (v) for v in cond.second) raise RuntimeError("Not Implemented Error") @@ -124,7 +126,7 @@ class FormWidget(object): _name=field.name, requires=field.requires, ) - if getattr(field,'show_if',None): + if getattr(field, 'show_if', None): trigger, cond = show_if(field.show_if) attr['_data-show-trigger'] = trigger attr['_data-show-if'] = cond @@ -191,9 +193,11 @@ class TimeWidget(StringWidget): class DateWidget(StringWidget): _class = 'date' + class DatetimeWidget(StringWidget): _class = 'datetime' + class TextWidget(FormWidget): _class = 'text' @@ -209,6 +213,7 @@ class TextWidget(FormWidget): attr = cls._attributes(field, default, **attributes) return TEXTAREA(**attr) + class JSONWidget(FormWidget): _class = 'json' @@ -226,6 +231,7 @@ class JSONWidget(FormWidget): attr = cls._attributes(field, default, **attributes) return TEXTAREA(**attr) + class BooleanWidget(FormWidget): _class = 'boolean' @@ -294,7 +300,7 @@ class ListWidget(StringWidget): _class = 'string' requires = field.requires if isinstance( field.requires, (IS_NOT_EMPTY, IS_LIST_OF)) else None - if isinstance(value,str): value = [value] + if isinstance(value, str): value = [value] nvalue = value or [''] items = [LI(INPUT(_id=_id, _class=_class, _name=_name, value=v, hideerror=k < len(nvalue) - 1, @@ -335,7 +341,7 @@ class RadioWidget(OptionsWidget): see also: `FormWidget.widget` """ - if isinstance(value, (list,tuple)): + if isinstance(value, (list, tuple)): value = str(value[0]) else: value = str(value) @@ -408,7 +414,7 @@ class CheckboxesWidget(OptionsWidget): attr = cls._attributes(field, {}, **attributes) attr['_class'] = add_class(attr.get('_class'), 'web2py_checkboxeswidget') - label = attr.get('label',True) + label = attr.get('label', True) requires = field.requires if not isinstance(requires, (list, tuple)): @@ -449,7 +455,7 @@ class CheckboxesWidget(OptionsWidget): requires=attr.get('requires', None), hideerror=True, _value=k, value=r_value), - LABEL(v, _for='%s%s' % (field.name, k)) + LABEL(v, _for='%s%s' % (field.name, k)) if label else '')) opts.append(child(tds)) @@ -522,7 +528,7 @@ class UploadWidget(FormWidget): download_url: url for the file download (default = None) """ - default = dict(_type='file',) + default = dict(_type='file', ) attr = cls._attributes(field, default, **attributes) inp = INPUT(**attr) @@ -555,7 +561,7 @@ class UploadWidget(FormWidget): else: inp = DIV(inp, SPAN('[', - A(current.T(cls.GENERIC_DESCRIPTION),_href=url), + A(current.T(cls.GENERIC_DESCRIPTION), _href=url), ']', _style='white-space:nowrap'), br, image) return inp @@ -814,6 +820,7 @@ def formstyle_bootstrap(form, fields): parent.append(DIV(label, _controls, _class='control-group', _id=id)) return parent + def formstyle_bootstrap3(form, fields): """ bootstrap 3 format form layout @@ -865,7 +872,7 @@ def formstyle_bootstrap3(form, fields): if _submit: # submit button has unwrapped label and controls, different class - parent.append(DIV(label, DIV(controls,_class="col-lg-4 col-lg-offset-2"), _class='form-group', _id=id)) + parent.append(DIV(label, DIV(controls, _class="col-lg-4 col-lg-offset-2"), _class='form-group', _id=id)) # unflag submit (possible side effect) _submit = False else: @@ -1224,7 +1231,7 @@ class SQLFORM(FORM): css = 'delete' for f in self.table.fields: on_del = self.table[f].ondelete - if isinstance(on_del,str) and 'cascade' in on_del.lower(): + if isinstance(on_del, str) and 'cascade' in on_del.lower(): css += ' cascade_delete' break widget = INPUT(_type='checkbox', @@ -1286,7 +1293,7 @@ class SQLFORM(FORM): for id, a, b, c in xfields: newrows = formstyle(id, a, b, c) self.field_parent[id] = getattr(b, 'parent', None) \ - if isinstance(b,XmlComponent) else None + if isinstance(b, XmlComponent) else None if type(newrows).__name__ != "tuple": newrows = [newrows] for newrow in newrows: @@ -1295,7 +1302,7 @@ class SQLFORM(FORM): table = formstyle(self, xfields) for id, a, b, c in xfields: self.field_parent[id] = getattr(b, 'parent', None) \ - if isinstance(b,XmlComponent) else None + if isinstance(b, XmlComponent) else None else: raise RuntimeError('formstyle not supported') return table @@ -1727,7 +1734,7 @@ class SQLFORM(FORM): else: ftype = field.type.split(' ')[0] if ftype.startswith('decimal'): ftype = 'double' - elif ftype=='bigint': ftype = 'integer' + elif ftype == 'bigint': ftype = 'integer' elif ftype.startswith('big-'): ftype = ftype[4:] # end options = search_options.get(ftype, None) @@ -1736,43 +1743,43 @@ class SQLFORM(FORM): field.label, str) and T(field.label) or field.label selectfields.append(OPTION(label, _value=str(field))) operators = SELECT(*[OPTION(T(option), _value=option) for option in options]) - _id = "%s_%s" % (value_id,name) + _id = "%s_%s" % (value_id, name) if field.type == 'boolean': - value_input = SQLFORM.widgets.boolean.widget(field,field.default,_id=_id) + value_input = SQLFORM.widgets.boolean.widget(field, field.default, _id=_id) elif field.type == 'double': - value_input = SQLFORM.widgets.double.widget(field,field.default,_id=_id) + value_input = SQLFORM.widgets.double.widget(field, field.default, _id=_id) elif field.type == 'time': - value_input = SQLFORM.widgets.time.widget(field,field.default,_id=_id) + value_input = SQLFORM.widgets.time.widget(field, field.default, _id=_id) elif field.type == 'date': iso_format = {'_data-w2p_date_format' : '%Y-%m-%d'} - value_input = SQLFORM.widgets.date.widget(field,field.default,_id=_id, **iso_format) + value_input = SQLFORM.widgets.date.widget(field, field.default, _id=_id, **iso_format) elif field.type == 'datetime': iso_format = iso_format = {'_data-w2p_datetime_format' : '%Y-%m-%d %H:%M:%S'} - value_input = SQLFORM.widgets.datetime.widget(field,field.default,_id=_id, **iso_format) + value_input = SQLFORM.widgets.datetime.widget(field, field.default, _id=_id, **iso_format) elif (field.type.startswith('reference ') or field.type.startswith('list:reference ')) and \ - hasattr(field.requires,'options'): + hasattr(field.requires, 'options'): value_input = SELECT( *[OPTION(v, _value=k) - for k,v in field.requires.options()], + for k, v in field.requires.options()], **dict(_id=_id)) elif field.type == 'integer' or \ field.type.startswith('reference ') or \ field.type.startswith('list:integer') or \ field.type.startswith('list:reference '): - value_input = SQLFORM.widgets.integer.widget(field,field.default,_id=_id) + value_input = SQLFORM.widgets.integer.widget(field, field.default, _id=_id) else: value_input = INPUT( _type='text', _id=_id, _class=field.type) new_button = INPUT( - _type="button", _value=T('New Search'), _class="btn btn-default", _title = T('Start building a new search'), - _onclick="%s_build_query('new','%s')" % (prefix,field)) + _type="button", _value=T('New Search'), _class="btn btn-default", _title=T('Start building a new search'), + _onclick="%s_build_query('new','%s')" % (prefix, field)) and_button = INPUT( - _type="button", _value=T('+ And'), _class="btn btn-default", _title = T('Add this to the search as an AND term'), + _type="button", _value=T('+ And'), _class="btn btn-default", _title=T('Add this to the search as an AND term'), _onclick="%s_build_query('and','%s')" % (prefix, field)) or_button = INPUT( - _type="button", _value=T('+ Or'), _class="btn btn-default",_title = T('Add this to the search as an OR term'), + _type="button", _value=T('+ Or'), _class="btn btn-default", _title=T('Add this to the search as an OR term'), _onclick="%s_build_query('or','%s')" % (prefix, field)) close_button = INPUT( _type="button", _value=T('Close'), _class="btn btn-default", @@ -1786,8 +1793,8 @@ class SQLFORM(FORM): _style='display:inline')) criteria.insert(0, SELECT( - _id=fields_id, - _onchange="jQuery('.w2p_query_row').hide();jQuery('#%s_'+jQuery('#%s').val().replace('.','-')).show();" % (field_id,fields_id), + _id=fields_id, + _onchange="jQuery('.w2p_query_row').hide();jQuery('#%s_'+jQuery('#%s').val().replace('.','-')).show();" % (field_id, fields_id), _style='float:left', *selectfields)) @@ -1805,14 +1812,13 @@ class SQLFORM(FORM): if(aggregator=='new') k.val(s); else k.val((v?(v+' '+ aggregator +' '):'')+s); } """ % dict( - prefix=prefix,fields_id=fields_id,keywords_id=keywords_id, - field_id=field_id,value_id=value_id - ) + prefix=prefix, fields_id=fields_id, keywords_id=keywords_id, + field_id=field_id, value_id=value_id + ) ) return CAT( DIV(_id=panel_id, _style="display:none;", *criteria), fadd) - @staticmethod def grid(query, fields=None, @@ -1972,7 +1978,7 @@ class SQLFORM(FORM): if user_signature: if not ( '/'.join(str(a) for a in args) == '/'.join(request.args) or - URL.verify(request,user_signature=user_signature, + URL.verify(request, user_signature=user_signature, hash_vars=False) or (request.args(len(args))=='view' and not logged)): session.flash = T('not authorized') @@ -2001,7 +2007,7 @@ class SQLFORM(FORM): _class=ui.get('buttontext'), cid=request.cid) - dbset = db(query,ignore_common_filters=ignore_common_filters) + dbset = db(query, ignore_common_filters=ignore_common_filters) tablenames = db._adapter.tables(dbset.query) if left is not None: if not isinstance(left, (list, tuple)): @@ -2012,21 +2018,21 @@ class SQLFORM(FORM): if fields: #add missing tablename to virtual fields for table in tables: - for k,f in table.iteritems(): - if isinstance(f,Field.Virtual): + for k, f in table.iteritems(): + if isinstance(f, Field.Virtual): f.tablename = table._tablename columns = [f for f in fields if f.tablename in tablenames] else: fields = [] columns = [] - filter1 = lambda f:isinstance(f,Field) - filter2 = lambda f:isinstance(f,Field) and f.readable + filter1 = lambda f:isinstance(f, Field) + filter2 = lambda f:isinstance(f, Field) and f.readable for table in tables: fields += filter(filter1, table) columns += filter(filter2, table) - for k,f in table.iteritems(): + for k, f in table.iteritems(): if not k.startswith('_'): - if isinstance(f,Field.Virtual) and f.readable: + if isinstance(f, Field.Virtual) and f.readable: f.tablename = table._tablename fields.append(f) columns.append(f) @@ -2039,7 +2045,7 @@ class SQLFORM(FORM): field_id = groupby.first #take the first groupby field table = field_id.table tablename = table._tablename - if not any(str(f)==str(field_id) for f in fields): + if not any(str(f) == str(field_id) for f in fields): fields = [f for f in fields]+[field_id] if upload == '': upload = lambda filename: url(args=['download', filename]) @@ -2069,8 +2075,8 @@ class SQLFORM(FORM): def linsert(lst, i, x): """Internal use only: inserts x list into lst at i pos:: - a = [1,2] - linsert(a, 1, [0,3]) + a = [1, 2] + linsert(a, 1, [0, 3]) a = [1, 0, 3, 2] """ lst[i:i] = x @@ -2174,14 +2180,14 @@ class SQLFORM(FORM): redirect(referrer, client_side=client_side_delete) exportManager = dict( - csv_with_hidden_cols=(ExporterCSV_hidden, 'CSV (hidden cols)',T('Comma-separated export including columns not shown; fields from other tables are exported as raw values for faster export')), - csv=(ExporterCSV, 'CSV',T('Comma-separated export of visible columns. Fields from other tables are exported as they appear on-screen but this may be slow for many rows')), - xml=(ExporterXML, 'XML',T('XML export of columns shown')), - html=(ExporterHTML, 'HTML',T('HTML export of visible columns')), - json=(ExporterJSON, 'JSON',T('JSON export of visible columns')), + csv_with_hidden_cols=(ExporterCSV_hidden, 'CSV (hidden cols)', T('Comma-separated export including columns not shown; fields from other tables are exported as raw values for faster export')), + csv=(ExporterCSV, 'CSV', T('Comma-separated export of visible columns. Fields from other tables are exported as they appear on-screen but this may be slow for many rows')), + xml=(ExporterXML, 'XML', T('XML export of columns shown')), + html=(ExporterHTML, 'HTML', T('HTML export of visible columns')), + json=(ExporterJSON, 'JSON', T('JSON export of visible columns')), tsv_with_hidden_cols= - (ExporterTSV, 'TSV (Spreadsheets, hidden cols)',T('Spreadsheet-optimised export of tab-separated content including hidden columns. May be slow')), - tsv=(ExporterTSV, 'TSV (Spreadsheets)',T('Spreadsheet-optimised export of tab-separated content, visible columns only. May be slow.'))) + (ExporterTSV, 'TSV (Spreadsheets, hidden cols)', T('Spreadsheet-optimised export of tab-separated content including hidden columns. May be slow')), + tsv=(ExporterTSV, 'TSV (Spreadsheets)', T('Spreadsheet-optimised export of tab-separated content, visible columns only. May be slow.'))) if not exportclasses is None: """ remember: allow to set exportclasses=dict(csv=False, csv_with_hidden_cols=False) to disable the csv format @@ -2202,20 +2208,20 @@ class SQLFORM(FORM): orderby = (order[:1] == '~' and ~sort_field) or sort_field expcolumns = [str(f) for f in columns] - selectable_columns = [str(f) for f in columns if not isinstance(f,Field.Virtual)] + selectable_columns = [str(f) for f in columns if not isinstance(f, Field.Virtual)] if export_type.endswith('with_hidden_cols'): #expcolumns = [] start with the visible columns, which includes visible virtual fields - selectable_columns=[] #like expcolumns but excluding virtual + selectable_columns = [] #like expcolumns but excluding virtual for table in tables: for field in table: if field.readable and field.tablename in tablenames: if not str(field) in expcolumns: expcolumns.append(str(field)) - if not(isinstance(field,Field.Virtual)): + if not(isinstance(field, Field.Virtual)): selectable_columns.append(str(field)) #look for virtual fields not displayed (and virtual method fields to be added here?) - for (field_name,field) in table.iteritems(): - if isinstance(field,Field.Virtual) and not str(field) in expcolumns: + for (field_name, field) in table.iteritems(): + if isinstance(field, Field.Virtual) and not str(field) in expcolumns: expcolumns.append(str(field)) if export_type in exportManager and exportManager[export_type]: @@ -2223,7 +2229,7 @@ class SQLFORM(FORM): try: #the query should be constructed using searchable fields but not virtual fields sfields = reduce(lambda a, b: a + b, - [[f for f in t if f.readable and not isinstance(f,Field.Virtual)] for t in tables]) + [[f for f in t if f.readable and not isinstance(f, Field.Virtual)] for t in tables]) dbset = dbset(SQLFORM.build_query( sfields, request.vars.get('keywords', ''))) rows = dbset.select(left=left, orderby=orderby, @@ -2233,11 +2239,11 @@ class SQLFORM(FORM): rows = [] else: rows = dbset.select(left=left, orderby=orderby, - cacheable=True, *selectable_columns) + cacheable=True, *selectable_columns) value = exportManager[export_type] clazz = value[0] if hasattr(value, '__getitem__') else value - rows.colnames = expcolumns # expcolumns is all cols to be exported including virtual fields + rows.colnames = expcolumns # expcolumns is all cols to be exported including virtual fields oExp = clazz(rows) filename = '.'.join(('rows', oExp.file_ext)) response.headers['Content-Type'] = oExp.content_type @@ -2373,17 +2379,17 @@ class SQLFORM(FORM): not all([isinstance(link, dict) for link in links]))) if include_buttons_column: if buttons_placement in ['right', 'both']: - headcols.append(TH(_class=ui.get('default',''))) + headcols.append(TH(_class=ui.get('default', ''))) right_cols += 1 if buttons_placement in ['left', 'both']: - headcols.insert(0, TH(_class=ui.get('default',''))) + headcols.insert(0, TH(_class=ui.get('default', ''))) left_cols += 1 head = TR(*headcols, **dict(_class=ui.get('header'))) cursor = True #figure out what page we are one to setup the limitby - if paginate and dbset._db._adapter.dbengine=='google:datastore': + if paginate and dbset._db._adapter.dbengine == 'google:datastore': cursor = request.vars.cursor or True limitby = (0, paginate) try: page = int(request.vars.page or 1)-1 @@ -2391,22 +2397,22 @@ class SQLFORM(FORM): elif paginate and paginate=1000: + if dbset._db._adapter.dbengine == 'google:datastore' and nrows >= 1000: message = T('at least %(nrows)s records found') % dict(nrows=nrows) else: message = T('%(nrows)s records found') % dict(nrows=nrows) - console.append(DIV(message or T('None'),_class='web2py_counter')) + console.append(DIV(message or T('None'), _class='web2py_counter')) paginator = UL() - if paginate and dbset._db._adapter.dbengine=='google:datastore': + if paginate and dbset._db._adapter.dbengine == 'google:datastore': #this means we may have a large table with an unknown number of rows. try: page = int(request.vars.page or 1)-1 except ValueError: page = 0 - paginator.append(LI('page %s'%(page+1))) + paginator.append(LI('page %s' % (page+1))) if next_cursor: d = dict(page=page+2, cursor=next_cursor) - if order: d['order']=order - if request.vars.keywords: d['keywords']=request.vars.keywords + if order: d['order'] = order + if request.vars.keywords: d['keywords'] = request.vars.keywords paginator.append(LI( - A('next',_href=url(vars=d),cid=request.cid))) - elif paginate and paginate\n\n\n\n\n%s\n\n' % (xml or '') + class ExporterXML(ExportClass): label = 'XML' file_ext = "xml" @@ -3261,6 +3273,7 @@ class ExporterXML(ExportClass): else: return '' + class ExporterJSON(ExportClass): label = 'JSON' file_ext = "json"