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). |