The view layer
The view layer describes the user interface. Views are defined using XML, which is used by the web client framework to generate data-aware HTML views.
We have menu items that can activate actions that can render views. For example, the
Users menu item processes an action also called Users, which in turn renders a series of views. There are several view types available, such as the list (sometimes called tree for historical reasons) and form views, and the filter options made available in the top-right search box are also defined by a particular type of view, the search view.
The Odoo development guidelines state that the XML files defining the user interface should be placed inside a
views/ subdirectory.
Let's start creating the user interface for our to-do application.
In the next sections, we will make gradual improvements and frequent module upgrades to make those changes available. You might also want to try the
--dev=all server option, which spares us from module upgrades while developing. Using it, the view definitions are read directly from the XML files so that your changes are immediately available to Odoo without the need for a module upgrade.Note
If an upgrade fails because of an XML error, don't panic! Read the error message in the server log carefully; it should point you to where the problem is. If you feel in trouble, just comment out the last edited XML portions or remove the XML file from
__manifest__.py and repeat the upgrade. The server should start correctly.
Now that we have the places to store our data, we want to have it available on the user interface. The first thing to do is add the corresponding menu options.
Edit the
views/library_menu.xml file and, inside the <odoo> XML element, add the records that define a menu item and the action performed by it: <!-- Action to open the Book list -->
<act_window id="action_library_book"
name="Library Books"
res_model="library.book"
view_mode="tree,form"
/>
<!-- Menu item to open the Book list -->
<menuitem id="menu_library_book"
name="Books"
parent="library_menu"
action="action_library_book"
/>
The user interface, including menu options and actions, is stored in database tables. The XML file is a data file used to load those definitions into the database when the addon module is installed or upgraded. The preceding code is an Odoo data file, describing two records to add to Odoo:
- The
<act_window>element defines a client-side window action that will open thelibrary.bookmodel with thetreeandformviews enabled, in that order - The
<menuitem>defines a top menu item that calls theaction_library_bookaction, which was defined before
We now need to upgrade the module again for these changes to take effect. Then, after a browser-page refresh, we should see the
Library top menu, and it should have a submenu option available. Clicking on it displays a basic list view, and records can be edited using an automatically-generated form view. We can see it if we click on the Createbutton:
Even though we haven't defined our user interface view, the automatically-generated list and form views are functional, and allow us to start editing data right away.
All views are stored in the database, in the
ir.ui.view model. To add a view to a module, we declare a <record> element describing the view in an XML file, which is to be loaded into the database when the module is installed.
Add this new
views/book_view.xml file to define the form view:<?xml version="1.0"?>
<odoo>
<record id="view_form_book" model="ir.ui.view">
<field name="name">Book Form</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<form string="Book"> <group>
<field name="name" />
<field name="author_ids" widget="many2many_tags" />
<field name="publisher_id" />
<field name="date_published" />
<field name="isbn" />
<field name="active" /> <field name="image" widget="image" />
</group>
</form>
</field>
</record>
</odoo>
The
ir.ui.view record has values for three fields: name, model, and arch. Another important element is the record id. It defines an XML ID identifier that can be used for other records to reference it.
The view is for the
library.book model and is named Book Form. The name is just for information purpose; it does not have to be unique, but it should allow you to easily identify which record it refers to. In fact, the name can be entirely omitted; in that case, it will be automatically generated from the model name and the view type.
The most important field is
arch, as it contains the view definition, highlighted in the previously listed XML code. The <form> tag defines the view type, and it contains the view structure.
In this case, it is the
<group> element that contains the fields to be shown in the form.The fields automatically use an appropriate default widget, such as the date-selection widget for date fields. In some cases, we may want to use a different widget. That is the case for author_ids, which is using a widget to display the authors as a list of tags, and the image field, which is using a widget appropriate for handling images. A detailed explanation of view elements is provided in Chapter 10, Backend Views – Design the User Interface.
Remember to add this new file to the
data key in the manifest file; otherwise, our module won't know about it and it won't be loaded:'data': [
'security/library_security.xml',
'security/ir.model.access.csv',
'views/library_menu.xml',
'views/book_view.xml',
],
Remember that, for the changes to be loaded to our Odoo database, a module upgrade is needed. To see the changes in the web client, the form needs to be reloaded. Either click again on the menu option that opens it or reload the browser page (F5 in most browsers).
The preceding section provided a basic form view, but we can make some improvements to it. For document models, Odoo has a presentation style that mimics a paper page. This form contains two elements:
<header>, to contain action buttons, and <sheet>, to contain data fields.<form>
<header>
<!-- Buttons will go here -->
</header>
<sheet>
<!-- Content goes here: -->
<group>
<field name="name" />
<field name="author_ids" widget="many2many_tags" />
<field name="publisher_id" />
<field name="date_published" />
<field name="isbn" />
<field name="active" />
<field name="image" widget="image" />
</group>
</sheet>
</form>
Forms can have buttons to perform actions. These buttons are able to run window actions such as opening another form or running Python functions defined in the model.
They can be placed anywhere inside a form, but for document-style forms, the recommended place for them is the
<header> section.
For our application, we will add a field for the book ISBN, and have a button to check whether the ISBN is valid. The code for this will be in a method of the Book model. We will name it
button_check_isbn().
Even though we don't have the method created yet, we can already add the corresponding button to the form:
<header>
<button name="button_check_isbn" type="object"
string="Check ISBN" />
</header>
- The
stringwith the text to display on the button - The
typeof action it performs nameis the identifier for that actionclassis an optional attribute to apply CSS styles, as in regular HTML
The
<group> tag allows you to organize form content. Placing <group> elements inside a <group> element creates a two-column layout inside the outer group. It is advisable for group elements to have a name attribute so that it's easier for other modules to extend them.
We will use this to better organize our content. Let's change the
<sheet> content of our form to match this:<sheet>
<group name="group_top">
<group name="group_left">
<field name="name" />
<field name="author_ids" widget="many2many_tags" />
<field name="publisher_id" />
<field name="date_published" />
</group>
<group name="group_right">
<field name="isbn" />
<field name="active" />
<field name="image" widget="image" />
</group>
</group>
</sheet>
<form>
<header>
<button name="check_isbn" type="object"
string="Check ISBN" />
</header>
<sheet>
<group name="group_top">
<group name="group_left">
<field name="name" />
<field name="author_ids" widget="many2many_tags" />
<field name="publisher_id" />
<field name="date_published" />
</group>
<group name="group_right">
<field name="isbn" />
<field name="active" />
<field name="image" widget="image" />
</group>
</group>
</sheet>
</form>
The action buttons won't work yet, since we still need to add their business logic.
When viewing a model in list mode, a
<tree> view is used. Tree views are capable of displaying lines organized in hierarchies, but most of the time, they are used to display plain lists.
We can add the following
<tree> view definition to book_view.xml:<record id="view_tree_book" model="ir.ui.view">
<field name="name">Book List</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<tree>
<field name="name"/>
<field name="author_ids" widget="many2many_tags" />
<field name="publisher_id"/>
<field name="date_published"/>
</tree>
</field>
</record>
This defines a list with four columns:
name, author_ids, publisher_id, and date_published.
At the top-right corner of the list, Odoo displays a search box. The fields it searches in and the available filters are defined by a
<search> view.
As before, we will add this to
book_view.xml:<record id="view_search_book" model="ir.ui.view">
<field name="name">Book Filters</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<search>
<field name="publisher_id"/>
<filter name="filter_inactive"
string="Inactive"
domain="[('active','=',True)]"/>
<filter name="filter_active"
string="Active"
domain="[('active','=',False)]"/>
</search>
</field>
</record>
The
<field> elements define fields that are also searched when typing in the search box. We added publisher_id to automatically suggest searching in the publisher field. The <filter> elements add predefined filter conditions, which can be toggled with a user click, are defined using a specific syntax. This will be addressed in more detail in Backend Views – Design the User Interface.Note
Changed in Odoo 12<filter> elements are now required to have a name="..." attribute, uniquely identifying each filter definition. If missing, the XML validation will fail and the module will not install or upgrade.
Comments
Post a Comment