def index(): dataset = db(db.product.id>0) ################################ The core ###################################### scope_1 = TableScope(dataset, db.product.status, renderstyle=True) rows_1 = scope_1.scoped_dataset.select() scope_2 = TableScope(dataset, db.product.status, all=False, default=2, scope_var='scope_2', renderstyle=True) rows_2 = scope_2.scoped_dataset.select() ################################################################################ return dict(sample_1=dict(table=SOLIDTABLE(rows_1, renderstyle=True), scope=scope_1), sample_2=dict(table=SOLIDTABLE(rows_2, renderstyle=True), scope=scope_2))
def index(): ################################ The core ###################################### tablecheckbox = TableCheckbox() # Insert an extra element to select an action tablecheckbox.components.insert( 0, SELECT('update', 'delete', _name='action', _style='width:70px;', requires=IS_IN_SET(['update', 'delete']))) if tablecheckbox.accepts(request.vars): # Selected record ids will be submitted session.flash = 'submitted %s' % tablecheckbox.vars redirect(URL('index')) extracolumns = [tablecheckbox.column()] ################################################################################ table = SOLIDTABLE(db(db.product.id > 0).select(), extracolumns=extracolumns, renderstyle=True) return dict(table=table, tablecheckbox=tablecheckbox)
def index(): records = db(db.product.id>0).select() table = SOLIDTABLE(records, renderstyle=True, _id='solidtable') ################################ The core ###################################### tablepermuter = TablePermuter(table.attributes['_id'], renderstyle=True) if tablepermuter.accepts(request.vars): # Permuted row indices will be submitted permuted_record_ids = [records[idx].id for idx in tablepermuter.vars.tablepermuter] session.flash = 'submitted : permuted_record_ids=%s' % permuted_record_ids redirect(URL('index')) ################################################################################ return dict(table=table, tablepermuter=tablepermuter)
def index(): query = db.product.id > 0 ################################ The core ###################################### paginate_selector = PaginateSelector(anchor='main') paginator = Paginator(paginate=paginate_selector.paginate, extra_vars={'v': 1}, anchor='main', renderstyle=True) paginator.records = db(query).count() paginate_info = PaginateInfo(paginator.page, paginator.paginate, paginator.records) rows = db(query).select(limitby=paginator.limitby()) ################################################################################ table = SOLIDTABLE(rows, renderstyle=True) return dict(table=table, paginator=paginator, paginate_selector=paginate_selector, paginate_info=paginate_info)
def index(): tax = db.product.price * 5 / 100 tax.represent = db.product.price.represent pretax_price = db.product.price + tax pretax_price.represent = db.product.price.represent request_headers = request.vars.headers or 'default' request_columns = request.vars.columns or 'default' ################################ The core ###################################### # A custom orderby selector for the solidtable. orderby_selector = OrderbySelector([ db.product.id, db.product.name, ~db.product.publish_start_date, ~pretax_price ]) rows = db().select(db.product.ALL, tax, pretax_price, orderby=orderby_selector.orderby()) if request_headers == 'default': # The "headers" is a dictionary of dictionaries for updating default values. # Custom fields such as "tax" can be passed to the dictionary keys. headers = { 'product.name': { 'selected': True }, 'product.description': { 'label': 'Details', 'class': 'italic', 'width': '200px', 'truncate': 38, }, tax: { 'label': 'Tax' }, pretax_price: { 'label': 'Pretax Price' } } else: # The "headers" can be 'labels' or 'fieldname:capitalize' headers = request_headers extracolumns = [ { 'label': A('Edit', _href='#'), 'content': lambda row, rc: A('Edit', _href='edit/%s' % row.product.id) }, { 'label': A('Delete', _href='#'), 'content': lambda row, rc: A('Delete', _href='delete/%s' % row.product.id) }, ] # The structure of "columns" defines the multi-line table layout # A "None" indicates an empty line over which the precedent line spans # Custom fields such as "tax" and extracolumns can be passed to the list of lists. if request_columns == 'default': columns = [ [db.product.name, extracolumns[0]], 'product.id', ['product.status', 'product.publish_start_date'], [None, 'product.publish_end_date'], [pretax_price, 'product.description'], [tax, None], ['product.price', None], ] elif request_columns == 'columns_2': columns = [ [db.product.name, extracolumns[0]], None, [pretax_price, 'product.description'], None, [tax, None], ] elif request_columns == 'columns_3': columns = [ [db.product.name, extracolumns[0]], [None, 'product.description'], [None, tax], ] table = SOLIDTABLE(rows, columns=columns, extracolumns=extracolumns, headers=headers, orderby=orderby_selector, renderstyle=True, linkto=URL('show'), selectid=lambda r: r.product.id == 7) ################################################################################ return dict(table=DIV(table, STYLE('.italic {font-style: italic;}')), table_args=DIV( A('headers=default', _href=URL(vars={'headers': 'default'})), ' ', A('headers=labels', _href=URL(vars={'headers': 'labels'})), ' ', A('headers=fieldname:capitalize', _href=URL(vars={'headers': 'fieldname:capitalize'})), ' ', A('columns=default', _href=URL(vars={'columns': 'default'})), ' ', A('columns=columns_2', _href=URL(vars={'columns': 'columns_2'})), ' ', A('columns=columns_3', _href=URL(vars={'columns': 'columns_3'})), ' ', ))
def __call__(self, query, fields=None, field_id=None, left=None, headers={}, columns=None, orderby=None, # EXTENDED for permutation searchable=True, # EXTENDED ex) [table.id, table.name, ...] sortable=True, # EXTENDED ex) [table.id, table.name, ...] paginate=(10, 25, 50, 100), # EXTENDED deletable=True, # EXTENDED ex) lambda record_id: deleted editable=True,# EXTENDED ex) [['id', 'name'], 'profile', ...] or lambda record: edit_form details=True,# EXTENDED ex) [['id', 'name'], 'profile', ...] or lambda record: view_form selectable=None, # TODO create=True, # EXTENDED ex) [['id', 'name'], 'profile', ...] or lambda: create_form csv=True, links=None, links_in_grid=True, upload = '<default>', args=[], user_signature = True, maxtextlengths={}, # NOT WORK maxtextlength=20, onvalidation=None, oncreate=None, onupdate=None, ondelete=None, sorter_icons=('[^]','[v]'), # NOT WORK ui='ui', # ONLY WORK FOR "ui" showbuttontext=True, _class="web2py_grid", formname='web2py_grid', search_widget='default', # NOT WORK extracolumns=None, # CUSTOM (same as in SQLTABLE) search_queries={}, # CUSTOM showid=True, # CUSTOM onpermute=None, # CUSTOM virtualtable=None, # CUSTOM virtualrecord=None, # CUSTOM virtualset=None, # CUSTOM hmac_key=None, # CUSTOM scope=None, #CUSTOM scope_default=None, #CUSTOM groupby=None, #CUSTOM ): from gluon.dal import SQLALL from plugin_solidform import SOLIDFORM from plugin_solidtable import SOLIDTABLE, OrderbySelector from plugin_paginator import Paginator, PaginateSelector, PaginateInfo gridbutton = self.settings.gridbutton recordbutton = self.settings.recordbutton request, session, T = current.request, current.session, current.T def __oncreate(form): session.flash = T('Created') def __onupdate(form): session.flash = T('Updated') def __ondelete(table, tablename, ret): session.flash = T('Deleted') def __onpermute(table, tablename, ret): session.flash = T('Permuted') def redirect_patch(): onupdate oncreate = oncreate or __oncreate onupdate = onupdate or __onupdate ondelete = ondelete or __ondelete onpermute = onpermute or __onpermute if ui == 'ui': ui = dict(widget='', header='', content='', default='', cornerall='', cornertop='', cornerbottom='', button='', buttontext='', buttonadd='ui-icon-plusthick', buttonback='ui-icon-arrowreturnthick-1-w', buttonexport='', buttondelete='ui-icon-close', buttonedit='ui-icon-pencil', buttontable='', buttonview='ui-icon-zoomin', ) elif not isinstance(ui,dict): raise RuntimeError,'SQLFORM.grid ui argument must be a dictionary' wenabled = (not user_signature or (session.auth and session.auth.user)) deletable = wenabled and deletable # if search_widget=='default': # search_widget = SQLFORM.search_menu url = self.url_factory(args, user_signature, hmac_key) db = query._db dbset = db(query) tables = [db[tablename] for tablename in db._adapter.tables(dbset.query)] if not fields: fields = reduce(lambda a,b:a+b, [[field for field in table] for table in tables]) new_fields = [] for item in fields: if isinstance(item,SQLALL): new_fields += item.table else: new_fields.append(item) fields = new_fields main_table = tables[0] if not field_id: field_id = main_table._id table = field_id.table tablename = table._tablename referrer = session.get('_web2py_grid_referrer_'+formname, url()) def __from_process_redirect_patch(func): def wrapper(form): func(form) redirect(referrer) return wrapper oncreate = __from_process_redirect_patch(oncreate) onupdate = __from_process_redirect_patch(onupdate) def check_authorization(): if user_signature or hmac_key: if not URL.verify(request,user_signature=user_signature, hmac_key=hmac_key): session.flash = T('not authorized') redirect(referrer) if upload=='<default>': upload = lambda filename: url(args=['download',filename]) if len(request.args)>1 and request.args[-2]=='download': check_authorization() stream = response.download(request,db) raise HTTP(200,stream,**response.headers) gridbuttons = [gridbutton('%(buttonback)s' % ui, T('Back'), referrer)] def _add_link_gridbuttons(record): if record and links: for link in links: if isinstance(link,dict): gridbuttons.append(link['body'](record)) elif link(record): gridbuttons.append(link(record)) if create and len(request.args)>1 and request.args[-2]=='new': check_authorization() table = db[request.args[-1]] if orderby: inverted = (orderby.op == orderby.db._adapter.INVERT) field = orderby.first if inverted else orderby last = dbset.select(field_id, field, limitby=(0,1), orderby=orderby.first if inverted else ~orderby).first() last_value = (last[field] or 0) if last else 0 table[field.name].default = (-1 if inverted else 1) + last_value self.mark_not_empty(virtualtable or table) if type(create) == type(lambda:None): create_form = create() else: create_form = SOLIDFORM(virtualtable or table, fields=create if type(create) in (list, tuple) else None, showid=showid, _class='web2py_form', submit_button=T('Create'), ).process(# next=referrer, for web2py-bug onvalidation=onvalidation, onsuccess=oncreate, formname=formname) self.unmark_not_empty(table) res = DIV(create_form, _class=_class) res.create_form = create_form res.gridbuttons = gridbuttons return res elif details and len(request.args)>2 and request.args[-3]=='view': check_authorization() table = db[request.args[-2]] record = table(request.args[-1]) or redirect(URL('error')) if type(details) == type(lambda:None): view_form = details(record) else: view_form = SOLIDFORM(virtualtable or table, virtualrecord or record, fields=details if type(details) in (list, tuple) else create if type(create) in (list, tuple) else None, upload=upload, readonly=True, showid=showid, _class='web2py_form') res = DIV(view_form, _class=_class) res.record = record # CUSTOM res.view_form = view_form # CUSTOM if editable: gridbuttons.append( gridbutton('%(buttonedit)s' % ui, T('Edit'), url(args=['edit', tablename, record.id])) ) _add_link_gridbuttons(record) res.gridbuttons = gridbuttons return res elif editable and len(request.args)>2 and request.args[-3]=='edit': check_authorization() table = db[request.args[-2]] record = table(request.args[-1]) or redirect(URL('error')) self.mark_not_empty(virtualtable or table) if type(editable) == type(lambda:None): edit_form = editable(record) else: edit_form = SOLIDFORM(virtualtable or table, virtualrecord or record, fields=editable if type(editable) in (list, tuple) else create if type(create) in (list, tuple) else None, upload=upload, deletable=deletable is True, showid=showid, delete_label=T('Check to delete:'), submit_button=T('Update'), _class='web2py_form').process( formname=formname, onvalidation=onvalidation, onsuccess=onupdate, # #next=referrer, for web2py-bug ) self.unmark_not_empty(table) res = DIV(edit_form,_class=_class) res.record = record # CUSTOM res.edit_form = edit_form if details: gridbuttons.append( gridbutton('%(buttonview)s' % ui, T('View'), url(args=['view', tablename, record.id])) ) _add_link_gridbuttons(record) res.gridbuttons = gridbuttons return res elif deletable and len(request.args)>2 and request.args[-3]=='delete': check_authorization() table = db[request.args[-2]] if type(deletable) == type(lambda:None): deletable(request.args[-1]) else: ret = db(table.id==request.args[-1]).delete() if ondelete: ondelete(table, request.args[-1], ret) redirect(url()) elif csv and len(request.args)>0 and request.args[-1]=='csv': check_authorization() # TODO return dict() elif request.vars.records and not isinstance(request.vars.records, list): request.vars.records=[request.vars.records] elif not request.vars.records: request.vars.records=[] session['_web2py_grid_referrer_'+formname] = URL( r=request, args=request.args,vars=request.vars, user_signature=user_signature, hmac_key=hmac_key) error = None search_form = None table_el_id = formname + '_maintable' columns = columns or [str(f) for f in fields if f.table==main_table and f.readable and (showid or f.type!='id')] if searchable: field_sep = '___' if searchable is True: _exclude_types = ('upload', 'text') if showid else ('id', 'upload', 'text') searchable = [f for f in fields if f.table==main_table and f.type not in _exclude_types and f.readable] _search_fields = [] _from_tos = [] for f in searchable: _requires = [] if f.requires and type(f.requires) not in (list, tuple): if isinstance(f.requires, IS_EMPTY_OR): _requires = [f.requires.other] else: _requires = [f.requires] _requires = [r for r in _requires if not isinstance(r, IS_NOT_IN_DB)] if _requires: if len(_requires) == 1: _requires = _requires[0] _requires = IS_EMPTY_OR(_requires) else: _requires = None _type = 'string' if f.type=='text' else 'integer' if f.type=='id' else f.type if (f.type in ('double', 'decimal', 'date', 'datetime') or (f.type == 'integer' and _requires and isinstance(_requires.other, (IS_INT_IN_RANGE)))): _from_to = [Field(str(f).replace('.', field_sep) + field_sep + 'from', type=_type, requires=_requires, label=f.label, widget=f.widget), Field(str(f).replace('.', field_sep) + field_sep + 'to', type=_type, requires=_requires, label=f.label, widget=f.widget)] _from_tos.append(_from_to) _search_fields += _from_to elif hasattr(f, 'table'): _search_fields.append(Field(str(f).replace('.', field_sep), type=_type, requires=_requires, label=f.label, widget=f.widget)) else: _search_fields.append(f) search_form = SQLFORM.factory( formstyle='divs', submit_button=T('Search'), _class='search_form', *_search_fields) for _from_to in _from_tos: self.inline(search_form, 'no_table', [f.name for f in _from_to], LABEL(_from_to[0].label), SPAN(' - ')) subquery = self._build_query_by_form(db, search_form, queries=search_queries, field_sep=field_sep, formname='search_%s' % formname) else: subquery = None if subquery: dbset = dbset(subquery) if scope: from plugin_tablescope import TableScope scope_el = TableScope(dbset, scope, default=scope_default) dbset = scope_el.scoped_dataset if sortable is True: sortable = [~f if f.type in ('id', 'date', 'datetime') else f for f in fields if f.table==main_table and f.type not in ('text', 'upload')] if not sortable: sortable = [] if orderby: sortable.insert(0, orderby) orderby_selector = OrderbySelector(sortable) current_orderby = orderby_selector.orderby() permutable = (orderby and (not subquery) and sortable and current_orderby is sortable[0]) extracolumns = extracolumns or [] _links_in_row_buttons = [] def _get_link_extracolumn(link): return {'label':link['header'], 'class':ui.get('default',''), 'content':lambda row, rc: link['body'](row)} if links and links_in_grid: for link in links: if isinstance(link, dict): extracolumns.append(_get_link_extracolumn(link)) else: _links_in_row_buttons.append(link) if permutable: if len(request.args)>2 and request.args[-3] in ('up', 'down'): check_authorization() table = db[request.args[-2]] record = table(request.args[-1]) or redirect(URL('error')) inverted = (orderby.op == orderby.db._adapter.INVERT) field = orderby.first if inverted else orderby current_value = record[field] if current_value is None: first = dbset.select(field_id, limitby=(0,1), orderby=orderby).first() current_value = (1 if inverted else -1) + (first.id if first else 0) if (request.args[-3] == ('down' if inverted else 'up')): target = dbset(field<current_value ).select(field_id, field, limitby=(0,1), orderby=orderby if inverted else ~orderby).first() elif (request.args[-3] == ('up' if inverted else 'down')): target = dbset(field>current_value ).select(field_id, field, limitby=(0,1), orderby=orderby.first if inverted else orderby).first() else: raise NotImplementedError if not target: last = dbset.select(field_id, limitby=(0,1), orderby=orderby.first if orderby.first else ~orderby).first() target_value = (-1 if inverted else 1) + (last.id if last else 0) else: target_value = target[field] db(table.id==record[field_id]).update(**{field.name:target_value}) if target: db(table.id==target[field_id]).update(**{field.name:current_value}) if onpermute: onpermute(table, request.args[-2], (record, target)) redirect(url()) first = dbset.select(field_id, limitby=(0,1), orderby=orderby).first() first_id = first.id if first else 0 last = dbset.select(field_id, limitby=(0,1), orderby=orderby.first if orderby.first else ~orderby).first() last_id = last.id if last else 0 extracolumns.append( {'label':DIV(T('Move'), _style='text-align:center;'), 'width':'150px' if showbuttontext else '65px', 'content':lambda row, rc: DIV(recordbutton('ui-icon-triangle-1-n', T('Up'), url(args=['up', tablename, row[field_id]]), showbuttontext) if row[field_id] != first_id else '', recordbutton('ui-icon-triangle-1-s', T('Down'), url(args=['down', tablename, row[field_id]]), showbuttontext) if row[field_id] != last_id else '', _style='text-align:center;')} ) if details or editable or deletable or _links_in_row_buttons: extracolumns.append( {'label':'', #'width':'%spx' % (_size + 12), 'content':lambda row, rc: DIV(_style='white-space:nowrap;', *([link(row) or '' for link in _links_in_row_buttons] + [recordbutton('%(buttonview)s' % ui, T('View'), url(args=['view', tablename, row[field_id]]), showbuttontext) if details else '', recordbutton('%(buttonedit)s' % ui, T('Edit'), url(args=['edit', tablename, row[field_id]]), showbuttontext) if editable else '', recordbutton('%(buttondelete)s' % ui, T('Delete'), url(args=['delete', tablename, row[field_id]]), showbuttontext, _onclick=""" if(confirm("%s")){return true;} else {jQuery(this).unbind('click').fadeOut();return false;}""" % T('Sure you want to delete them?'),) if deletable else '', ]) )} ) if paginate: paginate_selector = PaginateSelector(paginate if type(paginate) in (list, tuple) else [paginate]) current_paginate = paginate_selector.paginate paginator = Paginator(paginate=current_paginate) # TODO for groupby paginator.records = virtualset(dbset.query).count() if virtualset else dbset.count() paginate_info = PaginateInfo(paginator.page, paginator.paginate, paginator.records) limitby = paginator.limitby() else: limitby = None current_paginate = None # TODO # if paginator.records == 0: # error = 'Not Found' if virtualset: records = virtualset(dbset.query).select(left=left, limitby=limitby, orderby=current_orderby, groupby=groupby, *fields) records.db = virtualtable._db else: records = dbset.select(left=left, limitby=limitby, orderby=current_orderby, groupby=groupby, *fields) table = SOLIDTABLE(records, columns=columns, headers=headers, orderby=orderby_selector, truncate=maxtextlength, #TODO replace extracolumns=extracolumns, upload=upload) table.attributes['_class'] = 'solidtable' table.attributes['_id'] = table_el_id inner = [] if scope: inner.append(scope_el) if current_paginate: inner.append(DIV(paginate_info, _class='pagination_information')) inner.append(table) if current_paginate and paginator.records > current_paginate: inner.append(DIV(paginate_selector, paginator, _class='index_footer')) res = DIV(_class=_class, *inner) res.records = records res.search_form = search_form res.error = error res.gridbuttons = [] if create: res.gridbuttons.append( gridbutton('%(buttonadd)s' % ui, T('Add'), url(args=['new', tablename])) ) return res
def index(): if not request.args(0): form = SQLFORM(define_virtual_product_table(), formstyle='ul') if form.process(dbio=False).accepted: catalog.add_product(*filter_virtual_product_fields(form.vars)) session.flash = T('Record Created') redirect(URL()) extracolumns = [ { 'label': T('Sale price'), 'content': lambda row, rc: '%s - %s' % (row.variants and min([v.price for v in row.variants]), row. variants and max([v.price for v in row.variants])) if row.option_groups else row.variants and row.variants[0 ].price }, { 'label': T('Option groups'), 'content': lambda row, rc: ':'.join([og.name for og in row.option_groups]) or '*master*' }, { 'label': T('Options'), 'content': lambda row, rc: ', '.join([ ':'.join([o.name for o in v.options]) for v in row.variants ]) or '*master*' }, { 'label': T('View'), 'content': lambda row, rc: A('View', _href=URL('index', args=['view', row.id])) }, { 'label': T('Edit'), 'content': lambda row, rc: A('Edit', _href=URL('index', args=['edit', row.id])) }, { 'label': T('Delete'), 'content': lambda row, rc: A('Delete', _href=URL('index', args=['delete', row.id])) }, ] products = catalog.products_from_query(table_product.id > 0).select( orderby=~table_product.id) products = SOLIDTABLE(products, headers='labels', extracolumns=extracolumns) return dict(product_form=form, products=products, unit_tests=[A('basic test', _href=URL('test'))]) elif request.args(0) == 'edit': product_id = request.args(1) product = catalog.get_product(product_id, load_option_groups=False) if not product: raise HTTP(404) form = SQLFORM(define_virtual_product_table(product), product, upload=URL('download'), formstyle='ul') if form.process(dbio=False).accepted: catalog.edit_product(product_id, *filter_virtual_product_fields(form.vars)) session.flash = T('Record Updated') redirect(URL()) return dict(back=A('back', _href=URL('index')), product_form=form) elif request.args(0) == 'view': product_id = request.args(1) product = catalog.get_product(product_id) if not product: raise HTTP(404) form = SQLFORM(table_product, product, readonly=True, upload=URL('download')) option_groups = [r.name for r in product.option_groups] variants = [(':'.join([o.name for o in variant.options]) or '*master*') + ' -> ' + variant.sku for variant in product.variants] return dict(back=A('back', _href=URL('index')), product=form, product_option_groups=option_groups, variants=variants) elif request.args(0) == 'delete': product_id = request.args(1) catalog.remove_product(product_id) session.flash = T('Record Deleted') redirect(URL())
def __call__( self, query, fields=None, field_id=None, left=None, headers={}, columns=None, orderby=None, # EXTENDED for permutation searchable=True, # EXTENDED ex) [table.id, table.name, ...] sortable=True, # EXTENDED ex) [table.id, table.name, ...] paginate=(10, 25, 50, 100), # EXTENDED deletable=True, editable=True, # EXTENDED ex) [['id', 'name'], 'profile', ...] details=True, # EXTENDED ex) [['id', 'name'], 'profile', ...] selectable=None, # TODO create=True, # EXTENDED ex) [['id', 'name'], 'profile', ...] csv=True, links=None, upload='<default>', args=[], user_signature=True, maxtextlengths={}, # NOT WORK maxtextlength=20, onvalidation=None, oncreate=None, onupdate=None, ondelete=None, sorter_icons=('[^]', '[v]'), # NOT WORK ui='ui', # ONLY WORK FOR "ui" showbuttontext=True, _class="web2py_grid", formname='web2py_grid', search_widget='default', # NOT WORK extracolumns=None, # CUSTOM (same as in SQLTABLE) search_queries={}, # CUSTOM showid=True, # CUSTOM onpermute=None, # CUSTOM virtualtable=None, # CUSTOM virtualrecord=None, # CUSTOM virtualset=None, # CUSTOM hmac_key=None, # CUSTOM scope=None, #CUSTOM scope_default=None, #CUSTOM groupby=None, #CUSTOM ): from gluon.dal import SQLALL from plugin_solidform import SOLIDFORM from plugin_solidtable import SOLIDTABLE, OrderbySelector from plugin_paginator import Paginator, PaginateSelector, PaginateInfo gridbutton = self.gridbutton recordbutton = self.recordbutton request, session, T = current.request, current.session, current.T def __oncreate(form): session.flash = T('Created') def __onupdate(form): session.flash = T('Updated') def __ondelete(table, tablename, ret): session.flash = T('Deleted') def __onpermute(table, tablename, ret): session.flash = T('Permuted') def redirect_patch(): onupdate oncreate = oncreate or __oncreate onupdate = onupdate or __onupdate ondelete = ondelete or __ondelete onpermute = onpermute or __onpermute if ui == 'ui': ui = dict( widget='', header='', content='', default='', cornerall='', cornertop='', cornerbottom='', button='', buttontext='', buttonadd='ui-icon-plusthick', buttonback='ui-icon-arrowreturnthick-1-w', buttonexport='', buttondelete='ui-icon-close', buttonedit='ui-icon-pencil', buttontable='', buttonview='ui-icon-zoomin', ) elif not isinstance(ui, dict): raise RuntimeError, 'SQLFORM.grid ui argument must be a dictionary' wenabled = (not user_signature or (session.auth and session.auth.user)) deletable = wenabled and deletable # if search_widget=='default': # search_widget = SQLFORM.search_menu url = self.url_factory(args, user_signature, hmac_key) db = query._db dbset = db(query) tables = [ db[tablename] for tablename in db._adapter.tables(dbset.query) ] if not fields: fields = reduce(lambda a, b: a + b, [[field for field in table] for table in tables]) new_fields = [] for item in fields: if isinstance(item, SQLALL): new_fields += item.table else: new_fields.append(item) fields = new_fields main_table = tables[0] if not field_id: field_id = main_table._id table = field_id.table tablename = table._tablename referrer = session.get('_web2py_grid_referrer_' + formname, url()) def __from_process_redirect_patch(func): def wrapper(form): func(form) redirect(referrer) return wrapper oncreate = __from_process_redirect_patch(oncreate) onupdate = __from_process_redirect_patch(onupdate) def check_authorization(): if user_signature or hmac_key: if not URL.verify(request, user_signature=user_signature, hmac_key=hmac_key): session.flash = T('not authorized') redirect(referrer) if upload == '<default>': upload = lambda filename: url(args=['download', filename]) if len(request.args) > 1 and request.args[-2] == 'download': check_authorization() stream = response.download(request, db) raise HTTP(200, stream, **response.headers) gridbuttons = [gridbutton('%(buttonback)s' % ui, T('Back'), referrer)] if create and len(request.args) > 1 and request.args[-2] == 'new': check_authorization() table = db[request.args[-1]] self.mark_not_empty(virtualtable or table) if orderby: inverted = (orderby.op == orderby.db._adapter.INVERT) field = orderby.first if inverted else orderby last = dbset.select( field_id, field, limitby=(0, 1), orderby=orderby.first if inverted else ~orderby).first() last_value = (last[field] or 0) if last else 0 table[field.name].default = (-1 if inverted else 1) + last_value create_form = SOLIDFORM( virtualtable or table, fields=create if type(create) in (list, tuple) else None, showid=showid, _class='web2py_form', submit_button=T('Create'), ).process( # next=referrer, for web2py-bug onvalidation=onvalidation, onsuccess=oncreate, formname=formname) self.unmark_not_empty(table) res = DIV(create_form, _class=_class) res.create_form = create_form res.gridbuttons = gridbuttons return res elif details and len(request.args) > 2 and request.args[-3] == 'view': check_authorization() table = db[request.args[-2]] record = table(request.args[-1]) or redirect(URL('error')) form = SOLIDFORM(virtualtable or table, virtualrecord or record, fields=details if type(details) in (list, tuple) else create if type(create) in (list, tuple) else None, upload=upload, readonly=True, showid=showid, _class='web2py_form') res = DIV(form, _class=_class) res.record = record # CUSTOM res.view_form = form # CUSTOM if editable: gridbuttons.append( gridbutton('%(buttonedit)s' % ui, T('Edit'), url(args=['edit', tablename, record.id]))) res.gridbuttons = gridbuttons return res elif editable and len(request.args) > 2 and request.args[-3] == 'edit': check_authorization() table = db[request.args[-2]] record = table(request.args[-1]) or redirect(URL('error')) self.mark_not_empty(virtualtable or table) edit_form = SOLIDFORM( virtualtable or table, virtualrecord or record, fields=editable if type(editable) in (list, tuple) else create if type(create) in (list, tuple) else None, upload=upload, deletable=deletable, showid=showid, delete_label=T('Check to delete:'), submit_button=T('Update'), _class='web2py_form') self.unmark_not_empty(table) edit_form.process( formname=formname, onvalidation=onvalidation, onsuccess=onupdate, # #next=referrer, for web2py-bug ) res = DIV(edit_form, _class=_class) res.record = record # CUSTOM res.edit_form = edit_form if details: gridbuttons.append( gridbutton('%(buttonview)s' % ui, T('View'), url(args=['view', tablename, record.id]))) res.gridbuttons = gridbuttons return res elif deletable and len( request.args) > 2 and request.args[-3] == 'delete': check_authorization() table = db[request.args[-2]] ret = db(table.id == request.args[-1]).delete() if ondelete: ondelete(table, request.args[-1], ret) redirect(url()) elif csv and len(request.args) > 0 and request.args[-1] == 'csv': check_authorization() return dict() elif request.vars.records and not isinstance(request.vars.records, list): request.vars.records = [request.vars.records] elif not request.vars.records: request.vars.records = [] session['_web2py_grid_referrer_' + formname] = URL( r=request, args=request.args, vars=request.vars, user_signature=user_signature, hmac_key=hmac_key) error = None search_form = None table_el_id = formname + '_maintable' columns = columns or [ str(f) for f in fields if f.table == main_table and f.readable and (showid or f.type != 'id') ] if searchable: field_sep = '___' if searchable is True: _exclude_types = ('upload', 'text') if showid else ('id', 'upload', 'text') searchable = [ f for f in fields if f.table == main_table and f.type not in _exclude_types and f.readable ] _search_fields = [] _from_tos = [] for f in searchable: _requires = [] if f.requires and type(f.requires) not in (list, tuple): if isinstance(f.requires, IS_EMPTY_OR): _requires = [f.requires.other] else: _requires = [f.requires] _requires = [ r for r in _requires if not isinstance(r, IS_NOT_IN_DB) ] if _requires: if len(_requires) == 1: _requires = _requires[0] _requires = IS_EMPTY_OR(_requires) else: _requires = None _type = 'string' if f.type == 'text' else 'integer' if f.type == 'id' else f.type if (f.type in ('double', 'decimal', 'date', 'datetime') or (f.type == 'integer' and _requires and isinstance(_requires.other, (IS_INT_IN_RANGE)))): _from_to = [ Field(str(f).replace('.', field_sep) + field_sep + 'from', type=_type, requires=_requires, label=f.label, widget=f.widget), Field(str(f).replace('.', field_sep) + field_sep + 'to', type=_type, requires=_requires, label=f.label, widget=f.widget) ] _from_tos.append(_from_to) _search_fields += _from_to elif hasattr(f, 'table'): _search_fields.append( Field(str(f).replace('.', field_sep), type=_type, requires=_requires, label=f.label, widget=f.widget)) else: _search_fields.append(f) search_form = SQLFORM.factory(formstyle='divs', submit_button=T('Search'), _class='search_form', *_search_fields) for _from_to in _from_tos: self.inline(search_form, 'no_table', [f.name for f in _from_to], LABEL(_from_to[0].label), SPAN(' - ')) subquery = self.build_query_by_form(db, search_form, queries=search_queries, field_sep=field_sep, formname='search_%s' % formname) else: subquery = None if subquery: dbset = dbset(subquery) if scope: from plugin_tablescope import TableScope scope_el = TableScope(dbset, scope, default=scope_default) dbset = scope_el.scoped_dataset if sortable is True: sortable = [ ~f if f.type in ('id', 'date', 'datetime') else f for f in fields if f.table == main_table and f.type not in ('text', 'upload') ] if not sortable: sortable = [] if orderby: sortable.insert(0, orderby) orderby_selector = OrderbySelector(sortable) current_orderby = orderby_selector.orderby() permutable = (orderby and (not subquery) and sortable and current_orderby is sortable[0]) extracolumns = extracolumns or [] if permutable: if len(request.args) > 2 and request.args[-3] in ('up', 'down'): check_authorization() table = db[request.args[-2]] record = table(request.args[-1]) or redirect(URL('error')) inverted = (orderby.op == orderby.db._adapter.INVERT) field = orderby.first if inverted else orderby current_value = record[field] if current_value is None: first = dbset.select(field_id, limitby=(0, 1), orderby=orderby).first() current_value = (1 if inverted else -1) + (first.id if first else 0) if (request.args[-3] == ('down' if inverted else 'up')): target = dbset(field < current_value).select( field_id, field, limitby=(0, 1), orderby=orderby if inverted else ~orderby).first() elif (request.args[-3] == ('up' if inverted else 'down')): target = dbset(field > current_value).select( field_id, field, limitby=(0, 1), orderby=orderby.first if inverted else orderby).first() else: raise NotImplementedError if not target: last = dbset.select(field_id, limitby=(0, 1), orderby=orderby.first if orderby.first else ~orderby).first() target_value = (-1 if inverted else 1) + (last.id if last else 0) else: target_value = target[field] db(table.id == record[field_id]).update( **{field.name: target_value}) if target: db(table.id == target[field_id]).update( **{field.name: current_value}) if onpermute: onpermute(table, request.args[-2], (record, target)) redirect(url()) first = dbset.select(field_id, limitby=(0, 1), orderby=orderby).first() first_id = first.id if first else 0 last = dbset.select( field_id, limitby=(0, 1), orderby=orderby.first if orderby.first else ~orderby).first() last_id = last.id if last else 0 extracolumns.append({ 'label': DIV(T('Move'), _style='text-align:center;'), 'width': '150px' if showbuttontext else '65px', 'content': lambda row, rc: DIV( recordbutton('ui-icon-triangle-1-n', T('Up'), url(args=['up', tablename, row[field_id]]), showbuttontext) if row[field_id] != first_id else '', recordbutton('ui-icon-triangle-1-s', T('Down'), url(args=['down', tablename, row[field_id]]), showbuttontext) if row[field_id] != last_id else '', _style='text-align:center;') }) _size = 80 if showbuttontext else 25 _size = _size * (int(bool(details)) + int(bool(editable)) + int(bool(deletable))) if _size: extracolumns.append({ 'label': '', 'width': '%spx' % (_size + 12), 'content': lambda row, rc: DIV( recordbutton('%(buttonview)s' % ui, T('View'), url(args=['view', tablename, row[field_id]]), showbuttontext) if details else '', recordbutton('%(buttonedit)s' % ui, T('Edit'), url(args=['edit', tablename, row[field_id]]), showbuttontext) if editable else '', recordbutton( '%(buttondelete)s' % ui, T('Delete'), url(args=['delete', tablename, row[field_id]]), showbuttontext, _onclick=""" if(confirm("%s")){return true;} else {jQuery(this).unbind('click').fadeOut();return false;}""" % T('Sure you want to delete them?'), ) if deletable else '') }) if paginate: paginate_selector = PaginateSelector(paginate if type(paginate) in (list, tuple) else [paginate]) current_paginate = paginate_selector.paginate paginator = Paginator(paginate=current_paginate) # TODO for groupby paginator.records = virtualset( dbset.query).count() if virtualset else dbset.count() paginate_info = PaginateInfo(paginator.page, paginator.paginate, paginator.records) limitby = paginator.limitby() else: limitby = None current_paginate = None # TODO # if paginator.records == 0: # error = 'Not Found' if virtualset: records = virtualset(dbset.query).select(left=left, limitby=limitby, orderby=current_orderby, groupby=groupby, *fields) records.db = virtualtable._db else: records = dbset.select(left=left, limitby=limitby, orderby=current_orderby, groupby=groupby, *fields) table = SOLIDTABLE( records, columns=columns, headers=headers, orderby=orderby_selector, truncate=maxtextlength, #TODO replace extracolumns=extracolumns, upload=upload) table.attributes['_class'] = 'solidtable' table.attributes['_id'] = table_el_id inner = [] if scope: inner.append(scope_el) if current_paginate: inner.append(DIV(paginate_info, _class='pagination_information')) inner.append(table) if current_paginate and paginator.records > current_paginate: inner.append( DIV(paginate_selector, paginator, _class='index_footer')) res = DIV(_class=_class, *inner) res.records = records res.search_form = search_form res.error = error res.gridbuttons = [] if create: res.gridbuttons.append( gridbutton('%(buttonadd)s' % ui, T('Add'), url(args=['new', tablename]))) return res