doc/book/en/devweb/views/table.rst
changeset 7992 4ff9f25cb06e
parent 6343 4814d44405fc
child 8032 bcb87336c7d2
equal deleted inserted replaced
7991:dcc5a4d48122 7992:4ff9f25cb06e
     1 Table view
     1 Table views
     2 ----------
     2 -----------
     3 
     3 
     4 (:mod:`cubicweb.web.views.tableview`)
     4 .. automodule:: cubicweb.web.views.tableview
     5 
       
     6 *table*
       
     7     Creates a HTML table (`<table>`) and call the view `cell` for each cell of
       
     8     the result set. Applicable on any result set.
       
     9 
       
    10 *editable-table*
       
    11     Creates an **editable** HTML table (`<table>`) and call the view `cell` for each cell of
       
    12     the result set. Applicable on any result set.
       
    13 
       
    14 *cell*
       
    15     By default redirects to the `final` view if this is a final entity or
       
    16     `outofcontext` view otherwise
       
    17 
       
    18 
       
    19 API
       
    20 ```
       
    21 
       
    22 .. autoclass:: cubicweb.web.views.tableview.TableView
       
    23    :members:
       
    24 
     5 
    25 Example
     6 Example
    26 ```````
     7 ```````
    27 
     8 
    28 Let us take an example from the timesheet cube:
     9 Let us take an example from the timesheet cube:
    29 
    10 
    30 .. sourcecode:: python
    11 .. sourcecode:: python
    31 
    12 
    32     class ActivityTable(EntityView):
    13     class ActivityResourcesTable(EntityView):
    33         __regid__ = 'activitytable'
    14         __regid__ = 'activity.resources.table'
    34         __select__ = is_instance('Activity')
    15         __select__ = is_instance('Activity')
    35         title = _('activitytable')
       
    36 
    16 
    37         def call(self, showresource=True):
    17         def call(self, showresource=True):
    38             _ = self._cw._
       
    39             headers  = [_("diem"), _("duration"), _("workpackage"), _("description"), _("state"), u""]
       
    40             eids = ','.join(str(row[0]) for row in self.cw_rset)
    18             eids = ','.join(str(row[0]) for row in self.cw_rset)
    41             rql = ('Any R, D, DUR, WO, DESCR, S, A, SN, RT, WT ORDERBY D DESC '
    19             rql = ('Any R,D,DUR,WO,DESCR,S,A, SN,RT,WT ORDERBY D DESC '
    42                    'WHERE '
    20                    'WHERE '
    43                    '   A is Activity, A done_by R, R title RT, '
    21                    '   A is Activity, A done_by R, R title RT, '
    44                    '   A diem D, A duration DUR, '
    22                    '   A diem D, A duration DUR, '
    45                    '   A done_for WO, WO title WT, '
    23                    '   A done_for WO, WO title WT, '
    46                    '   A description DESCR, A in_state S, S name SN, A eid IN (%s)' % eids)
    24                    '   A description DESCR, A in_state S, S name SN, '
    47             if showresource:
    25                    '   A eid IN (%s)' % eids)
    48                 displaycols = range(7)
       
    49                 headers.insert(0, display_name(self._cw, 'Resource'))
       
    50             else: # skip resource column if asked to
       
    51                 displaycols = range(1, 7)
       
    52             rset = self._cw.execute(rql)
    26             rset = self._cw.execute(rql)
    53             self.wview('editable-table', rset, 'null',
    27             self.wview('resource.table', rset, 'null')
    54                        displayfilter=True, displayactions=False,
       
    55                        headers=headers, displaycols=displaycols,
       
    56                        cellvids={3: 'editable-final'})
       
    57 
    28 
    58 To obtain an editable table, specify 'edtitable-table' as vid. You
    29     class ResourcesTable(RsetTableView):
    59 have to select the entity in the rql request too (in order to kwnow
    30         __regid__ = 'resource.table'
    60 which entity must be edited). You can specify an optional
    31         # notice you may wish a stricter selector to check rql's shape
    61 `displaycols` argument which defines column's indexes that will be
    32         __select__ = is_instance('Resource')
    62 displayed. In the above example, setting `showresource` to `False`
    33         # my table headers
    63 will only render columns from index 1 to 7.
    34         headers  = ['Resource', 'diem', 'duration', 'workpackage', 'description', 'state']
       
    35         # I want a table where attributes are editable (reledit inside)
       
    36         finalvid = 'editable-final'
       
    37 
       
    38         cellvids = {3: 'editable-final'}
       
    39         # display facets and actions with a menu
       
    40         layout_args = {'display_filter': 'top',
       
    41                        'add_view_actions': None}
       
    42 
       
    43 To obtain an editable table, you may specify the 'editable-table' view identifier
       
    44 using some of `cellvids`, `finalvid` or `nonfinalvid`.
    64 
    45 
    65 The previous example results in:
    46 The previous example results in:
    66 
    47 
    67 .. image:: ../../images/views-table-shadow.png
    48 .. image:: ../../images/views-table-shadow.png
    68 
    49 
    69 
    50 In order to activate table filter mechanism, the `display_filter` option is given
    70 In order to activate table filter mechanism, set the `displayfilter`
    51 as a layout argument. A small arrow will be displayed at the table's top right
    71 argument to True. A small arrow will be displayed at the table's top
    52 corner. Clicking on `show filter form` action, will display the filter form as
    72 right corner. Clicking on `show filter form` action, will display the
    53 below:
    73 filter form as below:
       
    74 
    54 
    75 .. image:: ../../images/views-table-filter-shadow.png
    55 .. image:: ../../images/views-table-filter-shadow.png
    76 
    56 
    77 By the same way, you can display all registered actions for the
    57 By the same way, you can display additional actions for the selected entities
    78 selected entity, setting `displayactions` argument to True.
    58 by setting `add_view_actions` layout option to `True`. This will add actions
       
    59 returned by the view's :meth:`~cubicweb.web.views.TableMixIn.table_actions`.
       
    60 
       
    61 You can notice that all columns of the result set are not displayed. This is
       
    62 because of given `headers`, implying to display only columns from 0 to
       
    63 len(headers).
       
    64 
       
    65 Also Notice that the `ResourcesTable` view relies on a particular rql shape
       
    66 (which is not ensured by the way, the only checked thing is that the result set
       
    67 contains instance of the `Resource` type). That usually implies that you can't
       
    68 use this view for user specific queries (e.g. generated by facets or typed
       
    69 manually).
       
    70 
       
    71 
       
    72 So another option would be to write this view using
       
    73 :class:`~cubicweb.web.views.tableview.EntityTableView`, as below.
       
    74 
       
    75 
       
    76     class ResourcesTable(EntityTableView):
       
    77         __regid__ = 'resource.table'
       
    78         __select__ = is_instance('Resource')
       
    79         # table columns definition
       
    80         columns  = ['resource', 'diem', 'duration', 'workpackage', 'description', 'in_state']
       
    81         # I want a table where attributes are editable (reledit inside)
       
    82         finalvid = 'editable-final'
       
    83         # display facets and actions with a menu
       
    84         layout_args = {'display_filter': 'top',
       
    85                        'add_view_actions': None}
       
    86 
       
    87         def workpackage_cell(entity):
       
    88             activity = entity.reverse_done_in[0]
       
    89             activity.view('reledit', rtype='done_for', role='subject', w=w)
       
    90         def workpackage_sortvalue(entity):
       
    91             activity = entity.reverse_done_in[0]
       
    92             return activity.done_for[0].sortvalue()
       
    93 
       
    94         column_renderers = {
       
    95             'resource': MainEntityColRenderer(),
       
    96             'workpackage': EntityTableColRenderer(
       
    97                header='Workpackage',
       
    98                renderfunc=worpackage_cell,
       
    99                sortfunc=worpackage_sortvalue,),
       
   100             'in_state': EntityTableColRenderer(
       
   101                renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state),
       
   102                sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state),
       
   103          }
       
   104 
       
   105 Notice the following point:
       
   106 
       
   107 * `cell_<column>(w, entity)` will be searched for rendering the content of a
       
   108   cell. If not found, `column` is expected to be an attribute of `entity`.
       
   109 
       
   110 * `cell_sortvalue_<column>(entity)` should return a typed value to use for
       
   111   javascript sorting or None for not sortable columns (the default).
       
   112 
       
   113 * The :func:`etable_entity_sortvalue` decorator will set a 'sortvalue' function
       
   114   for the column containing the main entity (the one given as argument to all
       
   115   methods), which will call `entity.sortvalue()`.
       
   116 
       
   117 * You can set a column header using the :func:`etable_header_title` decorator.
       
   118   This header will be translated. If it's not an already existing msgid, think
       
   119   to mark it using `_()` (the example supposes headers are schema defined msgid).
       
   120 
       
   121 
       
   122 Pro/cons of each approach
       
   123 `````````````````````````
       
   124 :class:`EntityTableView` and :class:`RsetableView` provides basically the same
       
   125 set of features, though they don't share the same properties. Let's try to sum
       
   126 up pro and cons of each class.
       
   127 
       
   128 * `EntityTableView` view is:
       
   129 
       
   130   - more verbose, but usually easier to understand
       
   131 
       
   132   - easily extended (easy to add/remove columns for instance)
       
   133 
       
   134   - doesn't rely on a particular rset shape. Simply give it a title and will be
       
   135     listed in the 'possible views' box if any.
       
   136 
       
   137 * `RsetTableView` view is:
       
   138 
       
   139   - hard to beat to display barely a result set, or for cases where some of
       
   140     `headers`, `displaycols` or `cellvids` could be defined to enhance the table
       
   141     while you don't care about e.g. pagination or facets.
       
   142 
       
   143   - hardly extensible, as you usually have to change places where the view is
       
   144     called to modify the RQL (hence the view's result set shape).