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.response # the datasource result
grid.colnames # column names of datasource result
grid.total # the count of datasource result

For example, let's customize the footer:

grid.footer = lambda fields : TFOOT(TD("This is my footer" , 
                                               _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]

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 9 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 9 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 9 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 9 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 9 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 
show more comments

Hosting graciously provided by:
Python Anywhere