We have seen how to organize the content in a form, using structural components such as header, group, and notebook. Now we can take a closer look at the semantic components, fields and buttons, and what we can do with them.
View fields have a few attributes available for them. Most of them have values taken from their definition in the model, but these can be overridden in the view.
Attributes that are generic, and do not depend on the field type, are:
name
identifies the field database name.string
is the label text, to be used if we want to override the label text provided by the model definition.help
is a tooltip text shown when you hover the pointer over the field, and allows to override the help text provided by the model definition.placeholder
is a suggestion text to display inside the field.widget
allows us to override the default widget used for the field. We will explore the available widgets in a moment.options
is a JSON data structure with additional options for the widget and depends on what each widget supports.class
are the CSS classes to use for the field HTML rendering.nolabel="True"
prevents the automatic field label from being presented. It only makes sense for the fields inside a <group>
element and is often used along with a <label for="...">
element.invisible="True"
makes the field not visible, but it's data is fetched from the server and is available on the form.readonly="True"
makes the field non-editable on the form.required="True"
makes the field mandatory on the form.Attributes specific to some field types are:
password="True"
is used for text fields. It is displayed as a password field, masking the characters typed in.filename
is used for binary fields, and it is the name of the model field to be used to store the name of the uploaded file.mode
is used for one-to-many fields. It specifies the view type to use to display the records. By default, it is tree
, but can also be form
, kanban
, or graph
.The <label>
element can be used to better control the presentation of a field label. One case where this is used is to present the label only when the form is in edit mode:
<label for="name" class="oe_edit_only" />
When doing this, if the field is inside a <group>
element, we usually want to also set nolabel="True"
on it.
On relational fields, we can have some additional control on what the user can do. By default, the user can create new records from these fields (also known as "quick create") and open the related record form. This can be disabled using the options
field attribute:
options={'no_open': True, 'no_create': True}
The context and domain are also particularly useful on relational fields. The context can define the default values for the related records, and the domain can limit the selectable records. A common example is top have the list of records selectable in a field to depend on the current value for another field of the current record. The domain can be defined in the model, but it can also be overridden in the View.
Each field type is displayed in the form with the appropriate default widget. But additional alternative widgets are available to be used.
For text fields, we have the following widgets:
email
is used to make the e-mail text an actionable "mail to" address.url
is used to format the text as a clickable URL.html
is used to render the text as HTML content; in edit mode, it features a WYSIWYG editor to allow the formatting of the content without the need for using the HTML syntax.For numeric fields, we have the following widgets:
handle
is specifically designed for sequence fields in list views and displays a handle that allows you to drag lines to a custom order.float_time
formats a float field with time quantities as hours and minutes.monetary
displays a float field as the currency amount. It expects a currency_id
companion field, but another field name can be provided with options="{'currency_field': 'currency_id'}"
.progressbar
presents a float as a progress percentage and can be useful for fields representing a completion rate.For relational and selection fields, we have these additional widgets:
many2many_tags
displays values as a list of button-like labels.selection
uses the selection
field widget for a many-to-one field.radio
displays the selection
field options using radio buttons.kanban_state_selection
shows a semaphore light for the kanban state selection list. The normal state is represented in gray, done is represented in green, and any other state is represented in red.priority
represents the selection
field as a list of clickable stars. The selection options are usually a numeric digit.Buttons support these attributes:
icon
is for icon image to use in the button to display; unlike smart buttons, the icons available for regular buttons are limited to the ones available in addons/web/static/src/img/icons
.string
is the button text label, or the HTML alt
text when an icon is used.type
is the typo of the action to perform. Possible values are:
workflow
is used to trigger a workflow engine signal;object
is used for calling a Python method;action
is used to run a window action.name
identifies the specific action to perform, according to the chosen type: either a workflow signal name, a model method name, or the database ID of window action to run. The %(xmlid)d
formula can be used to translate the XML ID into the required Database ID.args
is used when the type
is object
, to pass additional parameters to the method.context
adds values to the context, that can have effects after the windows action is run, or in the Python code methods called.confirm
displays a confirmation message box, with the text assigned to this attribute.special="cancel"
is used on wizards, to cancel and close the wizard form.When designing the form structure, we included a top-right area to contain smart buttons. Let's now add a button inside it.
For our app, we will have a button displaying the total number of to-dos for the owner of the current to-do, and clicking on it would navigate to the list of those items.
First we need to add the corresponding computed field to models/todo_model.py
. Add to the TodoTask
class with the following:
def compute_user_todo_count(self): for task in self: task.user_todo_count = task.search_count( [('user_id', '=', task.user_id.id)]) user_todo_count = fields.Integer( 'User To-Do Count', compute='compute_user_todo_count')
Next we add the button box and the button inside it. Right after the end of the oe_title
DIV, replace the buttons box placeholder we added before, with the following:
<div name="buttons" class="oe_right oe_button_box"> <button class="oe_stat_button" type="action" icon="fa-tasks" name="%(action_todo_task_button)d" context="{'default_user_id': user_id}" help="All to-dos for this user" > <field string="To-Dos" name="user_todo_count" widget="statinfo"/> </button> </div>
This button displays the total number of To-do Tasks for the person responsible for this to-do task, computed by the user_todo_count
field.
These are the attributes that we can use when adding smart buttons:
class="oe_stat_button"
renders a rectangle instead of a regular button.icon
sets the icon to use, chosen from the Font Awesome set. Available icons can be browsed at http://fontawesome.io.type
and name
are the button type and the name of the action to trigger. For smart buttons the type will usually be action
, for a window action, and name
will be the ID of the action to execute. It expects an actual database ID, so we have to use a formula to convert an XML ID into a database ID: "%(action-external-id)d"
. This action should open a view with the related records.string
adds label text to the button. We have not used it here because the contained field already provides a text for it.context
should be used to set default values on the target view, to be used on new records created on the view after clicking through the button.help
adds a help tooltip displayed when the mouse pointer is over the button.The button
element itself is a container, with fields displaying statistics. Those are regular fields using the widget statinfo
. The field should be a computed field defined in the underlying model. Other than fields, inside a button we can also use static text, such as:
<div>User's To-dos</div>
When clicking on the button, we want to see a list with only the Tasks for the current responsible user. That will be done by the action_todo_task_button
action, not yet implemented. But it needs to know the current responsible user, to be able to perform the filter. For that we use the button's context
attribute to store that value.
The Action used must to be defined before the Form, so we should add it at the top of the XML file:
<act_window id="action_todo_task_button" name="To-Do Tasks" res_model="todo.task" view_mode="tree,form,calendar,graph,pivot" domain="[('user_id','=',default_user_id)]" />
Notice how we use the default_user_id
context key for the domain filter. This particular key will also set the default value on the user_id
field when creating new Tasks after following the button link.