Warning: Can't synchronize with repository "(default)" (Unsupported version control system "svn": No module named svn). Look in the Trac log for more information.

Changes between Version 6 and Version 7 of DataGridWidget


Ignore:
Timestamp:
02/13/06 03:17:26 (9 years ago)
Author:
max
Comment:

updated the docs for FastDataGrid?, advanced usage topic and customization

Legend:

Unmodified
Added
Removed
Modified
  • DataGridWidget

    v6 v7  
    11== Overview == 
    22 
    3 DataGrid helps you to present your data on a page in a tabular form. The data expected to be a list of objects and each row renders a single object. DataGrid can integrate nicely with fastdata controllers by providing inline links to edit or delete an object or create new object of the same type. DataGrid can also be configured to render data without editing links giving you simply a nice, tabular layout with minimal efforts. 
     3DataGrid helps you to present your data on a page in a tabular form. DataGrid's purpose is to render   a list of same-kind objects (such as a list of your model instances) in a nice, tabular layout with minimal efforts. The DataGrid subclass, FastDataGrid, integrates nicely with fastdata controllers by providing inline links to edit or delete an object or create new object of the same type.  
    44 
    5 == Basic usage == 
     5== Differences between !DataGrid and !FastDataGrid == 
    66 
    7 In a typical use case, you use DataGrid to render your model objects (SQLObject instances). The following snippet shows how DataGrid would be used to build simple user management form. 
     7DataGrid requires you to describe what you're going to display via ''fields'' parameter at construction fime. FastDataGrid is sophisticated enough to figure out how to display arbitrary SelectResults instance (this is what you get when you do .select() on you SQLObject's model object). 
     8 
     9They also have different Kid templates. DataGrid's template is very simple and on purpose -- the goal is to be easy to grasp and easy to extend/replace with a custom one. On the other hand, FastData template is much more sophisticated, designed to work within FastData environment. It is intended to be used "as is", giving the user certain hooks to customize its appearance. 
     10 
     11== Basic !DataGrid usage == 
     12 
     13Suppose you want to display a list of Users in your system. Here is a sample User declaration (note that it's not an SQLObject -- just a plain Python class): 
    814 
    915{{{ 
    1016#!python 
    11 from turbogears.fastdata.datawidgets import DataGrid 
     17class User: 
     18    def __init__(self, ID, name, emailAddress): 
     19        self.userId = ID 
     20        self.name = name 
     21        self.emailAddress = emailAddress 
     22    displayName = property(fget=lambda self: self.name.capitalize()) 
     23}}} 
     24 
     25Given the above definition, you may want to display Users in the following form: 
     26 
     27{{{ 
     28#!python 
     29from turbogears.widgets import DataGrid 
    1230 
    1331users_admin_form = DataGrid(fields=[ 
    14         ('ID', 'userId'), 
    15         ('Name', 'displayName'), 
    16         ('E-mail', 'emailAddress'), 
    17         ('Created on', 'created'), 
     32    ('ID', 'userId'), 
     33    ('Name', 'displayName'), 
     34    ('E-mail', 'emailAddress'), 
    1835]) 
    1936}}} 
    2037 
    21 The `fields` parameter define the header of the column and object's attribute to be put in that column; each tuple represents separate table column. 
     38As you have probably guessed, ''fields'' parameter defines what and how would be displayed by this DataGrid instance. Each tuple defines single column in the resulting table; first tuple's element defines column's title while second element defines ''accessor''. Accessor usually refers to attribute's name, such as User.userId or property's name, such as User.displayName of our model class.  
    2239 
    23 When DataGrid is rendered it is given the data to be shown. DataGrid then iterates through this data and draws each element as an individual table row. To fill the row it queries the object with a corresponding name, like 'displayName' or 'userId'. 
     40To display a users' table you pass a list of Users to the users_admin_form.display() method: 
    2441 
    25 == Customize cell's rendering == 
     42{{{ 
     43#!python 
     44users = [User(1, 'john', 'john@foo.net'), User(2, 'fred', 'fred@foo.net')] 
     45users_admin_form.display(users) 
     46}}} 
    2647 
    27 Sometimes simply displaying an attribute like 'displayName' is not enough. In case of TG_User object, for instance you may want to format nicely permissions a user posseses. To do this, you provide a callable object instead of the attribute name. The callable is then called with a row object and returned value is inserted in a table cell. 
     48Result will look something like this (just a bit prettier): 
     49 
     50{{{ 
     51#!html 
     52 <table border="0" cellpadding="0" cellspacing="3"> 
     53   <thead><td>ID</td><td>Name</td><td>E-mail</td></thead> 
     54   <tr><td>1</td><td>John</td><td>john@foo.net</td></tr> 
     55   <tr><td>2</td><td>Fred</td><td>fred@foo.net</td></tr> 
     56 </table> 
     57}}} 
     58 
     59== Fastdata integration == 
     60 
     61For a fastdata environment you're mostly likely to use FastDataGrid: 
     62 
     63{{{ 
     64#!python 
     65from turbogears.fastdata import DataController 
     66from turbogears.fastdata.datawidgets import FastDataGrid 
     67from model import TG_User 
     68 
     69class Root(controllers.RootController): 
     70    users = DataController(sql_class=TG_User, list_widget=users_admin_form) 
     71}}} 
     72 
     73Now if you access /users/ page you should see a table with a list of users, along with edit/delete icons and "Add a record" link at the bottom. 
     74 
     75Note that unlike plain DataGrid class you don't need to pass ''fields'' parameter to FastDataGrid. Instead, FastDataGrid able to inspect SelectResults instance it gets to extract SQLObject's metadata. In other words, FastDataGrid instance can easily render arbitrary SQLObjects while with DataGrid you need to list result fields explicitly. You may still want to pass ''fields'' parameter to FastDataGrid if you want to customize fields' representation: fields, their order and how they are displayed. 
     76 
     77{{{ 
     78#!python 
     79class Root(controllers.RootController): 
     80    users = DataController(sql_class=TG_User, 
     81        list_widget=users_admin_form, 
     82        list_template='.templates.admin_users') 
     83}}} 
     84 
     85Add something like this to your `admin_users` template: 
     86 
     87{{{ 
     88${list_widget.display(data, show_actions=False, add_link_title='Add User')} 
     89}}} 
     90 
     91== Customizing !FastDataGrid representation == 
     92 
     93You can tweak FastDataGrid's representation to a certain extent by passing configuration options at "display time" (when you call grid.display() from your template). The following options are supported: `show_actions`, `show_add_link`, `add_link_title`, `delete_link_msg`. I hope their meaning is self-explaining. Most up-to-date list of these options can be found at the top of datagrid.kid file at turbogears.fastdata.templates sub-package. 
     94 
     95== Customizing !DataGrid representation == 
     96 
     97Unlike, FastDataGrid, DataGrid's template provides no customization hook. On the other hand it is really simple and easy to understand so if you need to customize DataGrid's representation simply copy it and tweak as you see fit. To use your template with a DataGrid use ''template'' constructor parameter, just like with any Widget. 
     98 
     99== Advanced !DataGrid usage == 
     100 
     101In addition to simple DataGrid definition shown above, you can use ''fields'' parameter in a more "advanced" ways. 
     102 
     103=== Using callable instead of attribute name === 
     104 
     105Sometimes simply displaying an attribute like 'displayName' is not enough. In case of TG_User object, you may want to format nicely permissions a user posseses. To do this, you provide a callable object instead of the attribute name. The callable is then called with a row object and returned value is inserted in a table cell. 
    28106 
    29107Example: 
     
    32110#!python 
    33111def format_user_permissions(u): 
    34         # ok, nothing fancy here but you get the idea 
    35         return ', '.join(u.permissions)  
     112    # ok, nothing fancy here but you get the idea 
     113    # Hint: use Kid's XML function to return HTML markup. 
     114    return ', '.join(u.permissions)  
    36115 
    37116users_admin_form = DataGrid(fields=[ 
    38         ('ID', 'userId'), 
    39         ('Name', 'displayName'), 
    40         ('Permissions', format_user_permissions), 
     117    ('ID', 'userId'), 
     118    ('Name', 'displayName'), 
     119    ('Permissions', format_user_permissions), 
    41120]) 
    42121}}} 
    43122 
    44 Hint: you can use Kid's XML function to return a string with HTML markup. 
    45  
    46 == Fastdata integration == 
    47  
    48 Just for completeness, here is how you can use the above form with a FastData controller: 
     123Note that a parameterless method of your model class is a suitable callable object: 
    49124 
    50125{{{ 
    51126#!python 
    52 from turbogears.fastdata import DataController 
    53 from turbogears.fastdata.datawidgets import DataGrid 
    54 from model import TG_User 
     127class User: 
     128    # ... 
     129    def get_last_login(self): 
     130        "Returns last login's timestamp." 
    55131 
    56 class Root(controllers.RootController): 
    57     users = DataController(sql_class=TG_User, list_widget=users_admin_form) 
    58  
    59         # ... 
     132users_admin_form = DataGrid(fields=[ 
     133    ('ID', 'userId'), 
     134    ('Name', 'displayName'), 
     135    ('Last logged in', User.get_last_login), 
     136]) 
    60137}}} 
    61138 
    62 Now if you access /users/ page you should see a table with a list of users, along with edit/delete icons and "Add a record" link at the bottom. 
     139=== Using !DataGrid.Column === 
    63140 
    64 == Customizing !DataGrid representation == 
     141Instead of two-element tuple you can use an instance of !DataGrid.Column (or subclass thereof) when defining DataGrid's fields. This is only useful if you're using custom DataGrid template as well. 
    65142 
    66 You can tweak DataGrid's representation to a certain extent by passing configuration options in a grid.insert() call. The following options are supported: `show_actions`, `show_add_link`, `add_link_title`. I hope their meaning is self-explaining. Most up-to-date list of these options can be found at the top of datagrid.kid file at turbogears.fastdata.templates sub-package. 
     143The idea of the !DataGrid.Column is to be able to specify arbitrary additional ''options'' along with a column which are then used in template to alter template's logic. 
    67144 
    68 When DataGrid used with FastData you'd need to override default FastData list template to be able to provide your own that would insert a grid with the options you want: 
     145Example: 
    69146 
    70147{{{ 
    71148#!python 
    72 class Root(controllers.RootController): 
    73     users = DataController(sql_class=TG_User, 
    74                 list_widget=users_admin_form, 
    75         list_template='.templates.admin_users') 
     149users_admin_form = DataGrid(fields=[ 
     150    DataGrid.Column('id', 'userId', 'ID', 
     151        options=dict(sortable=True)), 
     152    DataGrid.Column('name', 'displayName', 'Name',  
     153        options=dict(sortable=True)), 
     154    DataGrid.Column('loggedin', 'get_last_login', 'Last logged in'), 
     155]) 
    76156}}} 
    77157 
    78 And something this goes to your `admin_users` template: 
     158Kid template: 
    79159 
    80160{{{ 
    81 #!html 
    82 ${list_widget.insert(data, show_actions=False, add_link_title='Add User')} 
     161  <div py:for="col in columns" py:strip="True"> 
     162    <?python sortable = col.get_option('sortable', False) ?> 
     163    ... 
     164    <a py:if="sortable" href="${geturl(sortby=col.name)}">${col.title}</a> 
     165    ... 
     166  </div> 
    83167}}} 
    84168 
    85 == Changing !DataGrid representation == 
     169=== Using !DataGrid without a 'model' === 
    86170 
    87 If shallow customization described above is not enough you can change it completely by using `template` parameter, just like with any other Widget. 
     171All the examples above assumed some model class, like User, being used to display in DataGrid. In fact, you can use DataGrid with any kind of data, not necessarily proper instances. The only "hindrance" is that you have to always specify a callable object as a field's accessor. Example: 
    88172 
    89 == Non-fastdata environment == 
     173{{{ 
     174#!python 
    90175 
    91 You can use DataGrid outside of fastdata environment without any extra efforts. 
     176grid = DataGrid(fields=[ 
     177    ('Name', lambda row: row[1]), 
     178    ('Country', lambda row: row[2]), 
     179    ('Age', lambda row: row[0]), 
     180]) 
    92181 
    93 The only thing you have to remember is that DataGrid expects an iterable that gives a list of objects. DataGrid doesn't care whether particular object is SQLObject instance or not as long as it can access specified object's attribute (even that is optional if you use a callable). 
     182data = [(33, "Anton Bykov", "Bulgaria"),  
     183    (23, "Joe Doe", "Great Britain"), (44, "Pablo Martelli", "Brazil")] 
     184grid.display(data) 
     185 
     186}}} 
    94187 
    95188== Error handling ==