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
    mrfreeze 15 years ago
    Thanks to Fran for recent improvements. The WebGrid is now datatables compliant (you must disable the add_link though).

  • 0
    mrfreeze 15 years ago
    Better, stronger, faster. It now supports multiple grids per page!

  • 0
    benigno 15 years ago
    Very very nice, usefull and absolutelly reusable. One thing, anyway to remove links? grid.action_links = [] grid.action_headers = [] drops an error, and with an empty string, gets badly formated. A thing I'd love in here would be a search, (server side) searching in all columns with "contains" or something like that. But I guess thats probably in the pipeline already. Thanks for this great module.

  • 0
    mrfreeze 15 years ago
    You found a bug! It is fixed now. I'm working on the search feature as we speak :)

  • 0
    alexandreandrade 15 years ago
    I have a problem when my page uses request.args. The links at the grid's header don't work. So I used this workaround: -------------------------- if request.args(0): session.request_var = request.args(0) ..... your code return(grid=grid()) else: arg = request.function + '/' + session.request_var + '?' vars = '' for var in request.vars.keys(): vars= vars + var + '=' + request.vars[var] + '&' vars = vars[:-1] arg = arg + vars redirect(arg) ------------------- the important thing to change is the value of request.args(0) in session.your_request.var. Would be good if Webgrid detects if has request.args and correct the link at header of table.
show more comments

Hosting graciously provided by:
Python Anywhere