Warning
Starting from CubicWeb version 4.0 all code related to generating html views has been moved to the Cube cubicweb_web.
If you want to migrate a project from 3.38 to 4.* while still using all the
html views you need to both install the cubicweb_web cube AND add it to
your dependencies and run add_cube('web')
.
cubicweb_web can be installed from pypi this way:
pip install cubicweb_web
We donât plan to maintain the features in cubicweb_web in the long run; we are moving to a full javascript frontend using both cubicweb_api (which exposes a HTTP API) and @cubicweb/client as a frontend javascript toolkit.
In the long run cubicweb_api will be merged inside of CubicWeb.
Table views#
Example#
Let us take an example from the timesheet cube:
class ActivityResourcesTable(EntityView):
__regid__ = 'activity.resources.table'
__select__ = is_instance('Activity')
def call(self, showresource=True):
eids = ','.join(str(row[0]) for row in self.cw_rset)
rql = ('Any R,D,DUR,WO,DESCR,S,A, SN,RT,WT ORDERBY D DESC '
'WHERE '
' A is Activity, A done_by R, R title RT, '
' A diem D, A duration DUR, '
' A done_for WO, WO title WT, '
' A description DESCR, A in_state S, S name SN, '
' A eid IN (%s)' % eids)
rset = self._cw.execute(rql)
self.wview('resource.table', rset, 'null')
class ResourcesTable(RsetTableView):
__regid__ = 'resource.table'
# notice you may wish a stricter selector to check rql's shape
__select__ = is_instance('Resource')
# my table headers
headers = ['Resource', 'diem', 'duration', 'workpackage', 'description', 'state']
# I want a table where attributes are editable (reledit inside)
finalvid = 'editable-final'
cellvids = {3: 'editable-final'}
# display facets and actions with a menu
layout_args = {'display_filter': 'top',
'add_view_actions': None}
To obtain an editable table, you may specify the âeditable-tableâ view identifier using some of cellvids, finalvid or nonfinalvid.
The previous example results in:
In order to activate table filter mechanism, the display_filter option is given as a layout argument. A small arrow will be displayed at the tableâs top right corner. Clicking on show filter form action, will display the filter form as below:
By the same way, you can display additional actions for the selected entities
by setting add_view_actions layout option to True. This will add actions
returned by the viewâs table_actions()
.
You can notice that all columns of the result set are not displayed. This is because of given headers, implying to display only columns from 0 to len(headers).
Also Notice that the ResourcesTable view relies on a particular rql shape (which is not ensured by the way, the only checked thing is that the result set contains instance of the Resource type). That usually implies that you canât use this view for user specific queries (e.g. generated by facets or typed manually).
So another option would be to write this view using
EntityTableView
, as below.
class ResourcesTable(EntityTableView):
__regid__ = 'resource.table'
__select__ = is_instance('Resource')
# table columns definition
columns = ['resource', 'diem', 'duration', 'workpackage', 'description', 'in_state']
# I want a table where attributes are editable (reledit inside)
finalvid = 'editable-final'
# display facets and actions with a menu
layout_args = {'display_filter': 'top',
'add_view_actions': None}
def workpackage_cell(entity):
activity = entity.reverse_done_in[0]
activity.view('reledit', rtype='done_for', role='subject', w=w)
def workpackage_sortvalue(entity):
activity = entity.reverse_done_in[0]
return activity.done_for[0].sortvalue()
column_renderers = {
'resource': MainEntityColRenderer(),
'workpackage': EntityTableColRenderer(
header='Workpackage',
renderfunc=workpackage_cell,
sortfunc=workpackage_sortvalue,),
'in_state': EntityTableColRenderer(
renderfunc=lambda w,x: w(x.cw_adapt_to('IWorkflowable').printable_state),
sortfunc=lambda x: x.cw_adapt_to('IWorkflowable').printable_state),
}
Notice the following point:
cell_<column>(w, entity) will be searched for rendering the content of a cell. If not found, column is expected to be an attribute of entity.
cell_sortvalue_<column>(entity) should return a typed value to use for javascript sorting or None for not sortable columns (the default).
The
etable_entity_sortvalue()
decorator will set a âsortvalueâ function for the column containing the main entity (the one given as argument to all methods), which will call entity.sortvalue().You can set a column header using the
etable_header_title()
decorator. This header will be translated. If itâs not an already existing msgid, think to mark it using _() (the example supposes headers are schema defined msgid).
Pro/cons of each approach#
EntityTableView
and RsetableView
provides basically the same
set of features, though they donât share the same properties. Letâs try to sum
up pro and cons of each class.
EntityTableView view is:
more verbose, but usually easier to understand
easily extended (easy to add/remove columns for instance)
doesnât rely on a particular rset shape. Simply give it a title and will be listed in the âpossible viewsâ box if any.
RsetTableView view is:
hard to beat to display barely a result set, or for cases where some of headers, displaycols or cellvids could be defined to enhance the table while you donât care about e.g. pagination or facets.
hardly extensible, as you usually have to change places where the view is called to modify the RQL (hence the viewâs result set shape).