If you benefit from web2py hope you feel encouraged to pay it forward by contributing back to society in whatever form you choose!

*UPDATE* This module is no longer maintained. Please use SQLFORM.grid instead.


Add the webgrid.py module to your modules folder (download at bottom)

In your model:

webgrid = local_import('webgrid')

In your controller:

def index():
    grid = webgrid.WebGrid(crud)
    grid.datasource = db(db.things.id>0)
    grid.pagesize = 10
    return dict(grid=grid()) #notice the ()

The datasource can be a Set, Rows, Table, or list of Table. Joins are also supported.

grid.datasource = db(db.things.id>0) #Set
grid.datasource = db(db.things.id>0).select() #Rows
grid.datasource = db.things #Table
grid.datasource = [db.things,db.others] #list of Table
grid.datasource = db(db.things.id==db.others.thing)# join

The main row components of the WebGrid are header, filter, datarow, pager, page_total, footer

You can link to crud functions using action_links. Just tell it where crud is exposed:

grid.crud_function = 'data'

You can turn rows on and off:

grid.enabled_rows = ['header','filter', 'pager','totals','footer','add_links']

You can control the fields and field headers:

grid.fields = ['things.name','things.location','things.amount']
grid.field_headers = ['Name','Location','Amount']

You can control the action links (links to crud actions) and action headers:

grid.action_links = ['view','edit','delete']
grid.action_headers = ['view','edit','delete']

You will want to modify crud.settings.[action]_next so that it redirects to your WebGrid page after completing:

if request.controller == 'default' and request.function == 'data':
    if request.args:
        crud.settings[request.args(0)+'_next'] = URL(r=request,f='index')

You can get page totals for numeric fields:

grid.totals = ['things.amount']

You can set filters on columns:

grid.filters = ['things.name','things.created']

You can modify the Query that filters use (not available if your datasource is a Rows object, use rows.find):

grid.filter_query = lambda f,v: f==v

You can control which request vars are allowed to override the grid settings:

grid.allowed_vars = ['pagesize','pagenum','sortby','ascending','groupby','totals']

The WebGrid will use a field's represent function if present when rendering the cell. If you need more control, you can completely override the way a row is rendered.

The functions that render each row can be replaced with your own lambda or function:

grid.view_link = lambda row: ...
grid.edit_link = lambda row: ...
grid.delete_link = lambda row: ...
grid.header = lambda fields: ...
grid.datarow = lambda row: ...
grid.footer = lambda fields: ...
grid.pager = lambda pagecount: ...
grid.page_total = lambda:

Here are some useful variables for building your own rows:

grid.joined # tells you if your datasource is a join
grid.css_prefix # used for css
grid.tablenames
grid.response # the datasource result
grid.colnames # column names of datasource result
grid.pagenum
grid.pagecount
grid.total # the count of datasource result

For example, let's customize the footer:

grid.footer = lambda fields : TFOOT(TD("This is my footer" , 
                                                      _colspan=len(grid.action_links)+len(fields),
                                                      _style="text-align:center;"),
                                               _class=grid.css_prefix + '-webgrid footer')

You can also customize messages:

grid.messages.confirm_delete = 'Are you sure?'
grid.messages.no_records = 'No records'
grid.messages.add_link = '[add %s]'
grid.messages.page_total = "Total:"

You can also also use the row_created event to modify the row when it is created. Let's add a column to the header:

def on_row_created(row,rowtype,record):
    if rowtype=='header':
        row.components.append(TH(' '))

grid.row_created = on_row_created

Let's move the action links to the right side:

def links_right(tablerow,rowtype,rowdata):
    if rowtype != 'pager':
        links = tablerow.components[:3]
        del tablerow.components[:3]
        tablerow.components.extend(links)

grid.row_created = links_right

alt text

If you are using multiple grids on the same page, they must have unique names.


Download webgrid.py

Download demo App

Related slices

Comments (112)

  • Login to post



  • 0
    hillmanov 13 years ago
    My table shows up on WebGrid, but the columns are much too wide to be useful. What is the best way to display 'thin' columns of integers. db.define_table('Commodity_Risk', Field('name','string'), Field('capacity','string'), Field('volatility','integer'), Field('bid_spread','integer'), Field('ask_spread','integer'), Field('low_limit','integer'), Field('high_limit','integer'), Field('volatility_surface','upload'), format = '%(name)s')

  • 0
    dymsza 14 years ago
    Tool is cool ;) but i have question is there any why to add owne action ? example: i have list of users and i want to have link to send email to user (next to edit link)

  • 0
    mrfreeze 14 years ago
    There are a couple ways. The easiest is to probably just modify the row when it's created:
    def add_mail_link(tablerow,rowtype,rowdata):
        if rowtype == 'datarow':
            mail_link = A(...)
            tablerow.components.insert(2, mail_link)
    grid.row_created = add_mail_link

  • 0
    iiit123 14 years ago
    will webgrid work for the following table too ? t=TABLE() t.append(TR(TD(value1),TD(value2),TD(value3),TD(value4))) ... ... ... grid.datasource=t thanks in advance...

  • 0
    mrfreeze 14 years ago
    The datasource must be a Set or Rows object like:
    db(db.things.id>0) #best way
    db(db.things.id>0).select() #slower way 

  • 0
    ammz 14 years ago
    Excelent Can you do a treeview for web2py ? best regards, António

  • 0
    mrfreeze 14 years ago
    @paulgerrard - If you can send me your model I can give you examples.

  • 0
    paulgerrard 14 years ago
    Hi again. Maybe being dim - but I'm not sure what your last comment means. Making filter_items_query the same as the datasource doesn't seem to have any effect on the values in the filter drop downs. Your comment "The filter_items_query isn't a subset of datasource." - that's what you are saying I guess. You've said the filter_query is for the results, not the values in the filter - so that's probably not a solution. So I'm thinking it is not possible to restrict the values in the filter drop downs to values that appear in the corresponding results column? Is that correct? The problem I have is one of my filters is names of people in the user's organisation, but this is a shared system with users from other organisations. The datasource only shows data from the current user's organisation so I need to limit the filter values to maintain confidentiality across organisations. If I can't limit the values, I can't use webgrid :O(

  • 0
    mrfreeze 14 years ago
    Fixed. Thanks!

  • 0
    toan75 14 years ago
    Thanks for this usefully module. In this code: grid.datasource = db(db.things.category==db.category.id) grid.fields = ['things.id','things.category','things.name', 'things.owner'] I can't change 'things.category' by 'category.name' ? (add other field of 'category' table) For many page, i had tiny changed: "for x in xrange(1, pagecount + 1)", instead: p1 = 1 if (self.pagenum<5) else self.pagenum-4 p2 = pagecount + 1 if (self.pagenum > pagecount -4) else self.pagenum + 6 if (p2<11) & (pagecount >10): p2 = 11 for x in xrange(p1, p2):

  • 0
    paulgerrard 14 years ago
    I have a complicated query as a data source and the filter drop downs contain items that aren't in the records displayed in the grid. I understand I should use the 'grid.filter_items_query' field and ave done - but it seems to make no difference. I get many more entries in the drop down than are in the grid. Here's the two lines of code that are relevant. Any ideas?
    grid.datasource = db((db.stories.priority_id==db.storypriority.id) & (db.stories.assigned_id==db.auth_user.id) & \
            (db.stories.status_id==db.storystatus.id) & (db.stories.app_id==db.applications.id) & \
            (db.applications.org_id==session.org_id))
        grid.filter_items_query = lambda field: (db.stories.app_id==db.applications.id) & (db.applications.org_id==session.org_id)
    

  • 0
    mrfreeze 14 years ago
    The filter_items_query isn't a subset of datasource. It's counter-intuitive but more flexible that way. You may need to modify the filter_query also.

  • 0
    ammz 14 years ago
    Now, it's works. Thank's a lot.

  • 0
    ammz 14 years ago
    Sometimes we have armazon1 or lente1 or lc4 But with this code: db.notas.vendedor.represent = lambda vendedor: auth_user.first_name db.notas.optometrista.represent = lambda optometrista: auth_user.first_name db.notas.armazon1.represent = lambda eyewear: [eyewear.marca,' ',eyewear.modelo,' ',eyewear.caract1] db.notas.lente1.represent = lambda lentes: [lentes.material,' ',lentes.tipo,' ',lentes.tecnoVisual,' ',lentes.tratamiento] db.notas.lc4.represent = lambda lc: [lc.tecnoGradua,' ',lc.marca,' ',lc.duracion,' ',lc.oftalmico,' ',lc.cosmetico] grid = webgrid.WebGrid(crud) grid.datasource = db((db.notas.entregado==False)&(db.notas.vendedor==db.auth_user.id)) grid.pagesize = 20 grid.enabled_rows = ['header','filter','pager','footer'] grid.fields = ['notas.nota','notas.armazon1','notas.lente1','notas.lc4','notas.total','notas.anticipo','notas.pagos','notas.saldo','notas.vendedor','notas.optometrista','notas.created_on'] grid.field_headers = ['Nota','Armazon1','Lente1','L/C1','Total','Antic.','Pagos','Saldo','Vendedor','Optomet.','Del'] grid.totals = ['notas.total','notas.anticipo','notas.pagos','notas.saldo'] grid.crud_function = 'data' grid.action_links = ['view'] grid.action_headers = ['Ver'] grid.filters = ['notas.nota'] grid.filter_items_query = lambda field: (db.notas.entregado==False)&(db.notas.vendedor==db.auth_user.id) grid.view_link= lambda row: A('view', _href= crud.url(f='show_nota', args=[row['id']])) grid.messages.page_info = 'Pagina %(pagenum)s de %(pagecount)s, existen un total de %(total)s registros' grid.messages.view_link = 'Ver' grid.messages.delete_link = 'Eliminar' grid.messages.edit_link = 'Editar' grid.messages.file_link = 'Archivo' grid.messages.previous_page = 'Anterior ' grid.messages.next_page = ' Siguiente' grid.messages.pagesize = ' Num. registros x pagina ' grid.messages.clear_filter = 'Limpiar filtros' grid.sortby = 'notas.nota' crud.settings.controller = 'ventas' I have this error: Traceback (most recent call last): File "/home/drayco/web2py/gluon/restricted.py", line 188, in restricted exec ccode in environment File "/home/drayco/web2py/applications/opticaluz/controllers/ventas.py", line 489, in File "/home/drayco/web2py/gluon/globals.py", line 96, in self._caller = lambda f: f() File "/home/drayco/web2py/gluon/tools.py", line 2277, in f return action(*a, **b) File "/home/drayco/web2py/applications/opticaluz/controllers/ventas.py", line 40, in leer_ventas return dict(gridnot=grid()) File "/home/drayco/web2py/applications/opticaluz/modules/webgrid.py", line 480, in __call__ r = field.represent(r) File "/home/drayco/web2py/applications/opticaluz/controllers/ventas.py", line 10, in db.notas.lc4.represent = lambda lc: [lc.tecnoGradua,' ',lc.marca,' ',lc.duracion,' ',lc.oftalmico,' ',lc.cosmetico] AttributeError: 'NoneType' object has no attribute 'tecnoGradua' Any advice? Or how can I avoid this error?

  • 0
    mrfreeze 14 years ago
    For some reason lc4 is null when it calls the represent function. I'm not sure if this is related to WebGrid. Can you try changing the represent for lc4 to this:
    db.notas.lc4.represent = lambda lc: [lc.tecnoGradua,' ',lc.marca,' ',lc.duracion,' ',lc.oftalmico,' ',lc.cosmetico] if lc else '' 

  • 0
    napoleonmr 14 years ago
    Good night sir. Thanks a lot for this power full tool. How about google application engine. I can't make it work on it. Do you have some advice about it?

  • 0
    mrfreeze 14 years ago
    I don't think joins are supported on GAE. Does your datasource involve a join? If not, what error are you getting?

  • 0
    mrfreeze 14 years ago
    Done. You can modify the label with:
    grid.messages.clear_filter = 'Clear All'

  • 0
    mrfreeze 14 years ago
    Good idea. I'll add it.

  • 0
    paulgerrard 14 years ago
    Using the grid - like it! One of my users asked me if he could have a 'clear all filters' button so he lists all records (having multiple drop downs already selected). I said I'd check. I know I could stick a link somewhere to revisit the page (as on first entry) to achieve this, but is there an option within Webgrid to display a button/link to do this?

  • 0
    smg 14 years ago
    @mr.freeze - Thank You! It's working now. PS. Is it possible to add version string to Webgrid, Please?

  • 0
    smg 14 years ago
    mr.freeze - if datasource defined as set, for example: db(db.things.id>0) #Set I must define grid.fields = ['things.name','things.location','things.amount'] or i got error in webgrid line 203: idfield = self.fields[0].split('.')[0] +'.id' IndexError: list index out of range. If use table as datasource, all works fine, without setting grid.fields.

  • 0
    mrfreeze 14 years ago
    @smg - A recent change broke this. Please re-download and try again. It should be working now.

  • 0
    ammz 14 years ago
    thank's a lot mr.freeze. With new version of web2py(2010-08-02) and without pagos.id, it's ok. I would like to suggest you, if it is possible to put a slide bar when we select many kind of registers, something like web2py->admin->database administration

  • 0
    hillmanov 14 years ago
    Mr. Freeze, I would like to add the option to use Ajax search functionality to filter the columns. If I work on a patch would you integrate it as an option to WebGrid? Thanks!

  • 0
    hillmanov 14 years ago
    In the case of large result sets, you may want to add an ellipsis for the page number list. For example, if you populate the database with 500 records, you will need to scroll to the right in order to see all of the page numbers, and it skews the output. So instead of listing 1, 2, 3, 4, 5, 6, etc., you would want to show 1, 2, 3, ..., 48, 49, 50.

  • 0
    mrfreeze 14 years ago
    @drayco - can you download webgrid.py and try again? You should be able to remove pagos.id without error.

  • 0
    mrfreeze 14 years ago
    This is odd. Can you do this as a test: grid.view_link = lambda row: str(row.keys()) and tell me what it shows in the view link?

  • 0
    mrfreeze 14 years ago
    Also, add pagos.id to grid.fields.

  • 0
    ammz 14 years ago
    Ok Headers
    
    Ver	Nota	Pago	Saldo	Entregado	Vendedor	pagos.vendedor
    
    
    In the list
    
    ['update_record', 'vendedor', 'entregadoEl', 'saldo', 'nota', 'pago', 'id', 'delete_record']	3	12090	1375.0	0.0	2010-06-03 15:46:39	ARACELI
    ['update_record', 'vendedor', 'entregadoEl', 'saldo', 'nota', 'pago', 'id', 'delete_record']	361	12047	0.0	0.0	2010-06-06 00:06:52	ARACELI
    ['update_record', 'vendedor', 'entregadoEl', 'saldo', 'nota', 'pago', 'id', 'delete_record']	362	12003	550.0	0.0	2010-06-05 00:34:00	ARACELI
    ['update_record', 'vendedor', 'entregadoEl', 'saldo', 'nota', 'pago', 'id', 'delete_record']	363	12013	300.0	0.0	2010-06-05 00:34:00	ARACELI
    
    
    If you like, I can send you an image and/or html field

  • 0
    mrfreeze 14 years ago
    Does the original grid.view_link work when id is in grid.fields?

  • 0
    ammz 14 years ago
    With this in controller:
    
    grid.fields = ['pagos.id','pagos.nota','pagos.pago','pagos.saldo','pagos.entregadoEl','pagos.vendedor']
    grid.field_headers = ['Num','Nota','Pago','Saldo','Entregado','Vendedor']
    grid.view_link= lambda row: A('view', _href= crud.url(f='show_entrega', args=[row['id']]))
    
    It's work. However, Can I don't show the id?

  • 0
    ammz 14 years ago
    No, I get this error
    
    Traceback (most recent call last):
      File "/home/drayco/web2py/gluon/restricted.py", line 178, in restricted
        exec ccode in environment
      File "/home/drayco/web2py/applications/seccion36_3_1/controllers/entregas.py", line 159, in 
      File "/home/drayco/web2py/gluon/globals.py", line 96, in 
        self._caller = lambda f: f()
      File "/home/drayco/web2py/gluon/tools.py", line 2221, in f
        return action(*a, **b)
      File "/home/drayco/web2py/applications/seccion36_3_1/controllers/entregas.py", line 157, in lee_entregas
        return dict(gridpag=grid())
      File "/home/drayco/web2py/applications/seccion36_3_1/modules/webgrid.py", line 431, in __call__
        for (rc, row) in enumerate(rows):
      File "/home/drayco/web2py/applications/seccion36_3_1/controllers/entregas.py", line 144, in 
        grid.view_link= lambda row: A('view', _href= crud.url(f='show_entrega', args=[row['id']]))
      File "/home/drayco/web2py/gluon/sql.py", line 661, in __getitem__
        return dict.__getitem__(self, key)
    KeyError: 'id'
    

  • 0
    ammz 14 years ago
    Hi, mr.freeze I have a litle problem, with web2py 1.81.5 and webgrid(2010-07-09) I can do this In Model
    db.define_table("pagos",
        Field("nota", 'integer', requires=IS_NOT_EMPTY(error_message='No puede estar vacio'), label='No. de Nota'),
        Field("pago", "double", requires=IS_NOT_EMPTY(error_message='No puede estar vacio')),
        Field("saldo", "double", default=0,writable=False),
        Field("vendedor",db.vendedores, requires=IS_IN_DB(vendedores,'vendedores.id','%(names)s %(apelPater)s %(apelMater)s')),
        Field('entregado','boolean', default=False),
        Field('entregadoEl', 'datetime', default=request.now, label='Entregado el'),
        Field("observaciones","string"))
    
    
    In Controller
    @auth.requires_membership('Capturista')
    def lee_entregas():
        Capturista = db(db.capturistas.creadoPor==auth.user.id).select()[0]
        db.pagos.vendedor.represent = lambda vendedores: vendedores.names
        grid = webgrid.WebGrid(crud)
        grid.datasource = db((db.pagos.vendedor==db.vendedores.id)&(db.vendedores.regional_id==Capturista.regional_id))
        grid.pagesize = 50
        grid.enabled_rows = ['header','filter','pager','footer']
        grid.fields = ['pagos.nota','pagos.pago','pagos.saldo','pagos.entregadoEl','pagos.vendedor']
        grid.field_headers = ['Nota','Pago','Saldo','Entregado','Vendedor']
    
        grid.crud_function = 'data' # Set the function where crud will be exposed.
        grid.action_links = ['view']
        grid.action_headers = ['Ver']
    
        grid.filters = ['pagos.nota']
        grid.filter_items_query = lambda field: (db.pagos.vendedor==db.vendedores.id)&(db.vendedores.regional_id==Capturista.regional_id)
    
        grid.view_link= lambda row: A('view', _href= crud.url(f='show_entrega', args=[row['pagos']['id']]))
    
        crud.settings.controller = 'entregas'
    
        return dict(gridpag=grid())
    
    
    But with web2py 1.81.5 and webgrid(2010-07-26), I get error in this line grid.view_link= lambda row: A('view', _href= crud.url(f='show_entrega', args=[row['pagos']['id']])) Can I do something to avoid that error?

  • 0
    mrfreeze 14 years ago
    What error do you get?

  • 0
    ammz 14 years ago
    ups, ok this is it
    Traceback (most recent call last):
      File "/home/drayco/web2py/gluon/restricted.py", line 178, in restricted
        exec ccode in environment
      File "/home/drayco/web2py/applications/seccion36_3_1/controllers/entregas.py", line 160, in 
      File "/home/drayco/web2py/gluon/globals.py", line 96, in 
        self._caller = lambda f: f()
      File "/home/drayco/web2py/gluon/tools.py", line 2221, in f
        return action(*a, **b)
      File "/home/drayco/web2py/applications/seccion36_3_1/controllers/entregas.py", line 158, in lee_entregas
        return dict(gridpag=grid())
      File "/home/drayco/web2py/applications/seccion36_3_1/modules/webgrid.py", line 441, in __call__
        tr.components.append(TD(self.view_link(row),
      File "/home/drayco/web2py/applications/seccion36_3_1/controllers/entregas.py", line 144, in 
        grid.view_link= lambda row: A('view', _href= crud.url(f='show_entrega', args=[row['pagos']['id']]))
      File "/home/drayco/web2py/gluon/sql.py", line 661, in __getitem__
        return dict.__getitem__(self, key)
    KeyError: 'pagos
    
    thank's in advanced

  • 0
    mrfreeze 14 years ago
    Does it work if you change?: args=[row['pagos']['id']] to: args=[row['id']]

  • 0
    mrfreeze 14 years ago
    @david - you're right, I need to get this under proper version control. I wasn't expecting people to use it! @yamandu - It's GPL2 so I encourage anyone to use and modify it. I actually wrote this at the request of Massimo to go into Crud but he hasn't had time to look at it.

  • 0
    villas 14 years ago
    Please try to add some version number into webgrid.py file so we can see what version we have. Thanks for great plugin!! David

  • 0
    yamandu 14 years ago
    In fact, this is not a plugin, as least as I know it. It is a module. But I always wanted to sugest or do myself this as a plugin. I think it would be very valuable if we join it jqgrid. We could eliminate weakness of both and join the strenght That´s my opinion!

  • 0
    hillmanov 14 years ago
    It takes over 8.5 seconds to render the response for a table containing 10,000 rows when talking to a MySQL database. I think I have identified "chattiness" in the code. If all fields are being selected (even though they will not be displayed as per the grid.fields parameter), I would not expect additional select statements outside of the COUNT(*) statement. The data is already in memory and just needs to be parsed. What does everyone think? Model snippet:
    db.define_table('allstats',
                    Field('pdate','datetime'),
                    Field('class','string',length=45),
                    Field('instance','string',length=45),
                    Field('parameter','string',length=45),
                    Field('hostname','string',length=45),
                    Field('lastv','double'),
                    Field('minv','double'),
                    Field('maxv','double'),
                    Field('avgv','double'),
                    Field('cntv','integer'),
                    Field('peaktime','datetime'),
                    Field('sumv','integer'),
                    Field('sitelocation','string',length=30),
                    migrate=False)
    webgrid = local_import('webgrid')
    
    Controller snippet:
    grid = webgrid.WebGrid(crud)
        grid.datasource = db(db.allstats.id<30000) # Set
        grid.crud_function = 'index' # Set the function where crud will be exposed.
        grid.fields = ['allstats.pdate','allstats.parameter','allstats.peaktime']
        grid.pagesize = 100
        return dict(grid=grid()) #notice the ()
    
    Wireshark capture from client:
    SET FOREIGN_KEY_CHECKS=1;
    SET sql_mode='NO_BACKSLASH_ESCAPES';
    SELECT allstats.id, allstats.pdate, allstats.class, allstats.instance, allstats.parameter, allstats.hostname, allstats.lastv, allstats.minv, allstats.maxv, allstats.avgv, allstats.cntv, allstats.peaktime, allstats.sumv, allstats.sitelocation FROM allstats WHERE allstats.id<30000 LIMIT 100 OFFSET 0;
    SELECT count(*) FROM allstats WHERE allstats.id<30000;
    SELECT allstats.id, allstats.pdate FROM allstats WHERE allstats.id>0;
    SELECT allstats.id, allstats.parameter FROM allstats WHERE allstats.id>0;
    SELECT allstats.id, allstats.peaktime FROM allstats WHERE allstats.id>0;
    commit
    

  • 0
    mrfreeze 14 years ago
    You are absolutely right! I updated it to select only the fields. Please add 'allstats.id' to your list of fields and try the updated module.

  • 0
    hillmanov 14 years ago
    Getting better! Would it be possible to eliminate the last three SELECT statements, since the data is obtained using the first SELECT? I think this might eliminate the extra network traffic and processing time. Wireshark capture:
    SET FOREIGN_KEY_CHECKS=1;
    SET sql_mode='NO_BACKSLASH_ESCAPES';
    SELECT allstats.id, allstats.pdate, allstats.parameter, allstats.peaktime FROM allstats WHERE allstats.id>48000 LIMIT 100 OFFSET 100;
    SELECT count(*) FROM allstats WHERE allstats.id>48000;
    SELECT allstats.id, allstats.id FROM allstats WHERE allstats.id>0;
    SELECT allstats.id, allstats.pdate FROM allstats WHERE allstats.id>0;
    SELECT allstats.id, allstats.parameter FROM allstats WHERE allstats.id>0;
    SELECT allstats.id, allstats.peaktime FROM allstats WHERE allstats.id>0;
    commit
    

  • 0
    mrfreeze 14 years ago
    These are for the filter row. I don't think there's a way to avoid making the extra selects since the filter values wouldn't be a subset of the datasource.

  • 0
    villas 14 years ago
    Thank you !!!!

  • 0
    villas 14 years ago
    is there a way, how can I specify default(initial) sort order?

  • 0
    villas 14 years ago
    I'm using WebGrid in Czech language application. I found there are several text strings not being externalized into settings. To change them, I have to modify source which is not good for upgrades. (e.g. previous, next and many others)

  • 0
    mrfreeze 14 years ago
    @david - You can use grid.sortby and grid.ascending to control the initial order. Which strings need to be externalized?

  • 0
    villas 14 years ago
    In current source there are lines like: total records ... ln. 349 prev/next ... lines 362, 363 and arround view/edit/delete ... lines 243,248,252 file ... ln. 458

  • 0
    mrfreeze 14 years ago
    Thanks David. You can now do:
        grid.messages.page_info = 'Page %(pagenum)s of %(pagecount)s Total %(total)s'
        grid.messages.view_link = 'View'
        grid.messages.delete_link = 'Delete'
        grid.messages.edit_link = 'Edit'
        grid.messages.file_link = 'File'
        grid.messages.previous_page = ' Previous'
        grid.messages.next_page = 'Next '
    

  • 0
    adsahay 14 years ago
    Hi mr.freeze, Any help on my query dated 2010-07-09 (including sum in fields)?

  • 0
    mrfreeze 14 years ago
    @adsahay - This isn't currently supported. I'll see what I can do to add it.

  • 0
    mrfreeze 14 years ago
    I think you need to include the table name with man_in_charge:
    grid.fields = ['task.title','task.man_in_charge'] 

  • 0
    frank 14 years ago
    oh, sorry for such mistake to borther you. thanks,

  • 0
    adsahay 14 years ago
    I have a datasource which has "sum", like:
    grid.datasource = db(db.things.id>0).select(db.things.inventory.sum())
    I get a key error in grid. How do I fix this?

  • 0
    ammz 14 years ago
    Hi mr.freeze: I have the same problem that frank 2010-07-08. Please, Can you give us a example about how to use grid.filter_query?

  • 0
    mrfreeze 14 years ago
    Whoops, grid.filter_query doesn't do what I thought. It is for controlling the query for filter results, not filter items. I'll have to add this.

  • 0
    mrfreeze 14 years ago
    Okay, I posted a new version. You can now do:
    grid.filter_items_query = lambda field: (db.invoice.entity==session.auth.user.id)&(field['id']>0)
    I also fixed a bug with clearing the filters.

  • 0
    ammz 14 years ago
    Thank's a lot, mr.freeze

  • 0
    frank 14 years ago
    thanks, mr.freeze, I'm just look into the source code of webgrid to figture that out. you save my time.

  • 0
    frank 14 years ago
    I still have other problem, if I have in model db.define_table('task', Field('title',length=128), ...... Field('man_in_charge',db.person,default=db.person.id,writable=True,readable=True), Field('description','text'), ) in controller, grid.fields = ['task.title','man_in_charge'] I got error as followings, if I move away man_in_charge in grid fields, it's ok. Traceback (most recent call last): File "D:\web2py cookbook\web2py\gluon\restricted.py", line 173, in restricted exec ccode in environment File "D:/web2py cookbook/web2py/applications/nano/controllers/default.py", line 659, in File "D:\web2py cookbook\web2py\gluon\globals.py", line 96, in self._caller = lambda f: f() File "D:\web2py cookbook\web2py\gluon\tools.py", line 1652, in f return action(*a, **b) File "D:/web2py cookbook/web2py/applications/nano/controllers/default.py", line 391, in list_task return dict(grid=grid(),person=person,form=form) File "D:\web2py cookbook\web2py\applications\nano\modules\webgrid.py", line 442, in __call__ r = row._extra[colname] File "D:\web2py cookbook\web2py\gluon\sql.py", line 664, in __getattr__ return dict.__getitem__(self,key) KeyError: '_extra' thanks for your advice

  • 0
    frank 14 years ago
    hi, mr.Freeze I got trouble on filter function, I have a database named db.invoice I define grid.datasource = db(db.invoice.entity==session.auth.user.id)(db.invoice.id>0) and grid.filters = ['invoice.name'] webgrid list works well. the problem is in the dropdown list of filter of invoice.name, it display all names of db.invoice, actually, it should display only those names by condition in datasource. I do not why?please advice. Frank

  • 0
    mrfreeze 14 years ago
    @frank - try changing the grid.filter_query to limit it to the values you want.

  • 0
    yamandu 14 years ago
    @mr.freeze - I solved it by not getting the rows, I mean, not doing .select() I passed only the query and it worked. So to define what fields would be visible I used the grid.fields settings.

  • 0
    yamandu 14 years ago
    Need help! I am getting AttributeError: 'list' object has no attribute 'find' in line 178 rows = rows.find(lambda row: row[flt_t][flt_f]==v) All grids that have single tables as datasources work perfectly but this has a join query as source. It crashes only when I try to use filter. Is that a bug or something else?

  • 0
    mrfreeze 14 years ago
    I think this is a bug in web2py's sql.py. I will post on the user group. Rows.find should always return a Rows object even if it is empty, not a list.

  • 0
    mrfreeze 14 years ago
    @yamandu - I sent a patch but in the meantime, you can just handle if your datasource is a list object manually.

  • 0
    yamandu 14 years ago
    Could you give some tips how to use webgrid with datatables and with LOAD?

  • 0
    apardue 14 years ago
    Ah, I had thought the name defaulted to the name of the grid rather than the controller (so .grid in my case rather than .index). I tried just now repeating the above but substituting the css as below, but it still didn't work.
    .index-webgrid footer {
        font-family: Arial;
        color: blue;
        }
    
    I then set the grid.css_prefix:
        grid.css_prefix = "index"
    
    But that also didn't effect anything. I just can't spot what I've missed. Thanks for your help.

  • 0
    apardue 14 years ago
    Having just retried I am able to style the grid as a whole using index-webgrid {}. But am still unable to modify the components within it.

  • 0
    apardue 14 years ago
    I was copying the above layout: {name}-webgrid {component}, when it should have been {name}-webgrid.{component} All sorted now and working - thanks.

  • 0
    apardue 14 years ago
    Hi - I have been using the grid for a while throughout a site I am building, and everything is working fine. However, when I tried to style it with CSS I was having no luck. In an attempt to get the simplest set up to identify what I'm doing wrong, I started a fresh web2py app called 'grid' and imported the webgrid module. I then and put in the model: db.define_table('mytable', Field('myname','string'), Field('mydob','date')) webgrid = local_import('webgrid') And in the default controller: def index(): grid = webgrid.WebGrid(crud) grid.datasource = db(db.mytable.id>0) grid.pagesize = 10 grid.footer = lambda fields : TFOOT(TD("This is my footer" , _colspan=len(grid.action_links)+len(fields), _style="text-align:center;"), _class=grid.css_prefix + '-webgrid footer') return dict(grid=grid()) And in the base.css: .grid-webgrid footer { background-color: blue; font-family: Arial; } The grid works fine, but the css isn't being applied. Can anyone help point out what I'm doing wrong? I'm pretty new to css and can't for the life figure out where I've messed up. Great slice - thanks in advance.

  • 0
    mrfreeze 14 years ago
    Have you set the grid.css_prefix? If not, the css_prefix will default to the name of the action that serves the grid (index in your case) so you would need to use .index-webgrid footer

  • 0
    kroitus 14 years ago
    Thank You! And now - maybe it is possible to make range filter? For example - from one date to another?

  • 0
    mrfreeze 14 years ago
    You can override the links to point to the expenses table:
    
    grid.view_link = lambda row: A('view', _href=crud.url(f=grid.crud_function, args=['read', 'expenses', row['expenses']['id'] ))
    grid.edit_link = lambda row: A('edit', _href=crud.url(f=grid.crud_function, args=['update', 'expenses', row['expenses']['id'] ))
    grid.delete_link = lambda row: A('delete', _href=crud.url(f=grid.crud_function, args=['delete', 'expenses', row['expenses']['id'] ))
    

  • 0
    kroitus 14 years ago
    Hello. Sorry for maybe dumb question, but I have simple situation: Two tables something like that:
    db.define_table('category',
       Field('name'))
    
    db.define_table('expenses',
       Field('amount', 'double'),
       Field('id_category', db.category, required=False),
       Field('user'))
    
    I want to display expenses.amount and category.name in one table, but only from specific user. When I use db(db.expenses.id_category==db.category.id), I can easily display field category.name, but it displays records from all users. When I use db(db.expenses.id_users=='user'), it selects records from specific user, but it only displays expenses.id_category. Tried expenses.id_category.name - doesn't work.

  • 0
    mrfreeze 14 years ago
    Not a dumb question. Try this:
    db.expenses.id_category.represent = lambda category: category.name
    query = (db.expenses.id_category==db.category.id) & (db.expenses.id_users=='user')
    grid.datasource = db(query)
    

  • 0
    kroitus 14 years ago
    Thanks. It worked. But now I have other problem. When I display all those records, edit and delete links are pointing not to record from expenses table, but from table category

  • 0
    rahuld 14 years ago
    Mr Freeze, The grid component works well. But slight ambiguity with crud interfaces for edit, view and delete. Here is my question. I want to link update_issue to update issues with id - http://127.0.0.1:8000/bugs/default/update_issue . now update_issue sits in default.py file. and this works well if I access it directly [http://127.0.0.1:8000/bugs/default/update_issue/1] and so on. This is the file where I have called webgrid component from I have specified
     grid.crud_function='update_issues'
    
    1- How do I make it work automatically after clicking the edit link. what would be the exact code to key in for grid.view_link = lambda row: A(...) ..? 2- Can we disable action links completely? 3- Sometimes it showed me 404 NOT FOUND error thought initially I worked it out 4- Can you prepare a short syntax of this very useful component as a technical ref. In the above I was unclear if "data" was a folder or a file Thanks Rahul

  • 0
    rahuld 14 years ago
    Never Mind I figured it out over webgrid group -- here is what I did so that new users are clear - Remember the example below is for datasource that is not a join. ---- here is the update issues stub -- Here i have defined my crud interface this is done in default.py
    def update_issues():
        mycrud = Crud(globals(), db)
        return dict(form=mycrud.update(db.issues, request.args(0)),
     
    now I've created update_issues.html already while calling this function using {{=form}} Here is the link that calls this function in default.py itself ...
    grid.edit_link= lambda row: A('edit', _href= mycrud.url(f='update_issues', args=[row['id']]))
    
    
    Now when ever I go to the link where I've defined my webgrid component and click edit, I get an editable page for my db. Its so cool.. Finally I thought this could help other novice users.

  • 0
    frank 14 years ago
    if we use sqlite database of other name for example "guide.db" instead of default"db" , it does not work.

  • 0
    mrfreeze 14 years ago
    By saying 'guide.db', your are implying that db is an attribute of guide but guide has not been declared. Remove the period and it should work.

  • 0
    frank 14 years ago
    may be misunderstood, I make something like this, in model: guide=SQLDB("sqlite://guide.db") guide.define_table('guidepost', SQLField('name'), .......) in controller, def index(): grid = webgrid.WebGrid(crud) grid.datasource = guide(guide.guidepost.id>0) grid.pagesize = 10 return dict(grid=grid()) with error "KeyError: 'guidepost'", it does not work. if I use default "db" database, it works.

  • 0
    mrfreeze 14 years ago
    I have a project using WebGrid with a database instance named 'musicdb' and it works. Can you possibly send me your project as a w2p file so I can debug?

  • 0
    m3tr0 14 years ago
    Any plan to handle also legacy tables (i.e. tables without 'id' column)? Thank you!

  • 0
    mrfreeze 14 years ago
    @adsahay - This is the easiest way I can think to do it for question 1: def links_right(tablerow,rowtype,rowdata): if rowtype != 'pager': links = tablerow.components[:3] del tablerow.components[:3] tablerow.components.extend(links) grid.row_created = links_right For question 2, I would put it in your model.

  • 0
    mrfreeze 14 years ago
    BTW, 'grid.row_created = links_right' isn't part of the links_right function. It just got formatted that way. 'grid.row_created = links_right' should go in your controller where you instantiate WebGrid. Also, the reason to modify crud.settings.[action]_next in your model is that the models are executed on every request.

  • 0
    adsahay 14 years ago
    Thanks! Works well.

  • 0
    adsahay 14 years ago
    Firstly thanks for this module...this is awesome. I have a couple of newbie questions: 1) How can I make the action links appear after the date (in rightmost columns) instead of left? 2) Where do I modify crud.settings.[action]_next, in data?

  • 0
    yamandu 14 years ago
    It is not working when there is a reference field. Looks like it fails to parse webgrid to html. Why?

  • 0
    mrfreeze 14 years ago
    @yamandu - I'm looking into this but in the meantime try setting a represent attribute on your reference fields: db.myfield.represent = lambda v: v.name

  • 0
    mrfreeze 14 years ago
    Found it! It should work now. Thanks.

  • 0
    yamandu 14 years ago
    It works perfectly now! I put a represent to take a field from the referenced table and it looks great! From now I want to figure the datatables thing and need to localize webgrid bo Brazilian Portuguese. Thanks again and again Mr Freeze!

  • 0
    yamandu 14 years ago
    Thanks again!

  • 0
    johannspies 14 years ago
    A further question about action links and 'def data()'. How can I define and use a separate function for each of the action links? I don't want to use "data". The "edit" link for example gave me the following error while the others not: TypeError: 'NoneType' object is not callable In the documentation I did not see that 'data' exposes any update function. Am I correct? So how do I define and use my own functions for "read", "edit", "delete", "create"?
show more comments

Hosting graciously provided by:
Python Anywhere