[IMP] reference/user_interface: reformat and clarify views reference

In particular, the following changes are made:
- Use the `class` and `attribute` admonitions along with custom
  attributes to define classes, views' root attributes, views'
  components, and attribute values. This allows re-using the responsive
  design that was made for reference lists, and getting rid of the
  previous implementation that relied on class attributes, which were not
  intended for this usage and reduce readability while hindering further
  contributions due to a lack of flexibility (no admonitions,
  sub-attributes...)
- Use definition lists to define view types to allow for clearer and
  longer descriptions.
- Rewrite and restructure the explanations when there is a lack clarity.
- Extract duplicated content to included RST files.
- Display SVG images into dedicated admonitions.
- Fix RST and English mistakes.
- Rename `view_architecture` to `view_architectures`, as it lists all
  existing architectures and doesn't describe "the architecture of a
  view".
- Replace underscores with hyphens in image file names to improve SEO.

task-3458320

closes odoo/documentation#5237

closes odoo/documentation#7497

X-original-commit: a17eaf4c6f
Signed-off-by: Antoine Vandevenne (anv) <anv@odoo.com>
This commit is contained in:
Antoine Vandevenne (anv) 2023-07-25 17:24:49 +02:00
parent db3db3c727
commit 14c0438764
55 changed files with 4365 additions and 4300 deletions

View File

@ -108,7 +108,7 @@ layout.
========================================
Now that we have created our assets bundle, we need to create a
:ref:`QWeb view<reference/view_architecture/qweb>` that uses that assets bundle.
:ref:`QWeb view <reference/view_architectures/qweb>` that uses that assets bundle.
.. code-block:: xml

View File

@ -236,7 +236,7 @@ Defines an ``ir.ui.menu`` record with a number of defaults and fallbacks:
``template``
------------
Creates a :ref:`QWeb view <reference/view_architecture/qweb>` requiring only the ``arch``
Creates a :ref:`QWeb view <reference/view_architectures/qweb>` requiring only the ``arch``
section of the view, and allowing a few *optional* attributes:
``id``

View File

@ -1112,7 +1112,7 @@ Provides information about Odoo models via its various fields.
list of the model's fields through a :class:`~odoo.fields.One2many` to
:ref:`reference/webservice/inspection/fields`
``view_ids``
:class:`~odoo.fields.One2many` to the :doc:`../reference/user_interface//view_architecture`
:class:`~odoo.fields.One2many` to the :doc:`../reference/user_interface/view_architectures`
defined for the model
``access_ids``
:class:`~odoo.fields.One2many` relation to the

View File

@ -675,7 +675,7 @@ Request-based
Most Python-side uses of QWeb are in controllers (and during HTTP requests),
in which case templates stored in the database (as
:ref:`views <reference/view_architecture/qweb>`) can be trivially rendered by calling
:ref:`views <reference/view_architectures/qweb>`) can be trivially rendered by calling
:meth:`odoo.http.HttpRequest.render`:
.. code-block:: python

View File

@ -8,6 +8,6 @@ User interface
:titlesonly:
user_interface/view_records
user_interface/view_architecture
user_interface/view_architectures
user_interface/scss_inheritance
user_interface/icons

View File

@ -1,5 +1,7 @@
:hide-page-toc:
.. _reference/user_interface/ui_icons:
========
UI icons
========

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
.. attribute:: context
:noindex:
The context that is merged into the view's context when performing the button's call, as a Python
expression that evaluates to a dict.
.. example::
.. code-block:: xml
<button name="button_confirm" type="object" context="{'BUSINESS_KEY': ANY}" string="LABEL"/>
:requirement: Optional
:type: :ref:`Python expression <reference/view_architectures/python_expression>`
:default: `{}`

View File

@ -0,0 +1,13 @@
.. attribute:: help
:noindex:
The tooltip message shown when hovering with the mouse cursor.
.. example::
.. code-block:: xml
<button type="object" name="remove" icon="fa-trash" help="Revoke"/>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,14 @@
.. attribute:: icon
:noindex:
The icon to use to display the button. See :ref:`icons <reference/user_interface/ui_icons>` for
the reference list.
.. example::
.. code-block:: xml
<button type="object" name="remove" icon="fa-trash"/>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,9 @@
.. attribute:: name
:noindex:
The method to call if the `type` is `object`. The :term:`XMLID <external identifier>` of the
action to load if the `type` is `action`, either in raw format or in `%(XMLID)d` format.
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,13 @@
.. attribute:: string
:noindex:
The button's text if there is no `icon`, the `alt` text for the icon otherwise.
.. example::
.. code-block:: xml
<button type="object" name="action_create_new" string="Create document"/>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,26 @@
.. attribute:: type
:noindex:
The type of the button indicating how it behaves. It can have two different values:
.. attribute:: object
:noindex:
Call a method on the view's model. The button's `name` is the method that is called with the
current record ID and the current `context`.
.. attribute:: action
:noindex:
Load and execute an `ir.actions` action record. The button's `name` is the XMLID of the
action to load. The `context` is extended with the view's model (as `active_model`) and with
the current record (as `active_id`).
.. example::
.. code-block:: xml
<button type="object" name="action_create_new" string="Create document"/>
<button type="action" name="addon.action_create_view" string="Create and Edit"/>
:requirement: Mandatory if the `special` attribute is not set
:type: str

View File

@ -0,0 +1,7 @@
.. attribute:: name
:noindex:
The name of the field to render.
:requirement: Mandatory
:type: str

View File

@ -0,0 +1,15 @@
.. attribute:: readonly
:noindex:
Whether the field can be modified by the user (`False`) or is read-only (`True`), as a Python
expression that evaluates to a bool.
.. example::
.. code-block:: xml
<field name="fname_a" readonly="True"/>
<field name="fname_b" readonly="name_a in [fname_b, parent.fname_d]"/>
:requirement: Optional
:type: :ref:`Python expression <reference/view_architectures/python_expression>`
:default: `False`

View File

@ -0,0 +1,15 @@
.. attribute:: required
:noindex:
Whether the field can be left empty (`False`) or must be set (`True`), as a Python expression
that evaluates to a bool.
.. example::
.. code-block:: xml
<field name="fname_a" required="True"/>
<field name="fname_b" required="fname_c != 3"/>
:requirement: Optional
:type: :ref:`Python expression <reference/view_architectures/python_expression>`
:default: `False`

View File

@ -0,0 +1,8 @@
.. attribute:: string
:noindex:
The label of the field.
:requirement: Optional
:type: str
:default: The `string` attribute of the model's field

View File

@ -0,0 +1,21 @@
.. attribute:: widget
:noindex:
The rendering method and context to use in place of the default one assigned to the field's type
(e.g., :class:`~odoo.fields.Char`, :class:`~odoo.fields.Many2one`). See
:ref:`reference/js/widgets`.
.. example::
.. code-block:: xml
<form>
<field name="tag_ids" widget="many2many_tags"/>
</form>
<tree>
<field name="sequence" widget="handle"/>
<field name="level_progress" widget="progressbar"/>
</tree>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,34 @@
.. attribute:: class
:noindex:
The `HTML class <https://en.wikipedia.org/wiki/HTML_attribute>`_ to set on the generated element.
The styling uses the `Bootstrap <https://getbootstrap.com>`_ framework and :ref:`UI icons
<reference/user_interface/ui_icons>`. Common Odoo classes include:
- `oe_inline`: prevents the usual line break following fields, and limits their span;
- `oe_left`, `oe_right`: `floats <https://developer.mozilla.org/en-US/docs/Web/CSS/float>`_ the
element to the corresponding direction;
- `oe_read_only`, `oe_edit_only`: only displays the element in the corresponding form mode;
- `oe_avatar`: for image fields, displays images as an "avatar" (max 90x90 square);
- `oe_stat_button`: defines a particular rendering to dynamically display information while being
clickable to target an action.
.. example::
.. code-block:: xml
<field name="fname" class="oe_inline oe_left oe_avatar"/>
.. example::
.. code-block:: xml
<button type="object" name="ACTION" class="oe_stat_button" icon="FONT_AWESOME" help="HELP">
<div class="o_field_widget o_stat_info">
<span class="o_stat_value"><FIELD/></span>
<span class="o_stat_text">TEXT</span>
</div>
</button>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,17 @@
.. attribute:: column_invisible
:noindex:
Whether the column is visible (`False`) or hidden (`True`), as a Python expression that evaluates
to a bool.
Unlike `invisible`, it affects the entire column, and is evaluated without the subtree values.
.. example::
.. code-block:: xml
<field name="product_is_late" column_invisible="parent.has_late_products == False"/>
<button type="object" name="action_confirm" column_invisible="context.get('hide_confirm')"/>
:requirement: Optional
:type: :ref:`Python expression <reference/view_architectures/python_expression>`
:default: `False`

View File

@ -0,0 +1,16 @@
.. attribute:: groups
:noindex:
The comma-separated list of user groups to whom the element is displayed. Users who do not belong
to at least one of these groups are unable to see the element. Groups can be prefixed with the
negative `!` operator to exclude them.
.. example::
.. code-block:: xml
<field name="FIELD_NAME" groups="base.group_no_one,!base.group_multi_company"/>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,28 @@
.. attribute:: invisible
:noindex:
Whether the element is visible (`False`) or hidden (`True`), as a Python expression that
evaluates to a bool.
.. note::
There are two uses for the `invisible` attribute:
- Usability: to avoid overloading the view and to make it easier for the user to read,
depending on the content.
- Technical: a field must be present (invisible is enough) in the view to be used in a
Python expression.
.. example::
.. code-block:: xml
<field name="fname_a" invisible="True"/> <!-- necessary to evaluate invisible attribute of 'fname_b' field -->
<field name="fname_b" invisible="fname_c != 3 and fname_a == parent.fname_d"/>
<group invisible="fname_c != 4">
<field name="fname_c"/>
<field name="fname_d"/>
<group>
:requirement: Optional
:type: :ref:`Python expression <reference/view_architectures/python_expression>`
:default: `False`

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1,44 @@
.. attribute:: banner_route
:noindex:
The route to fetch HTML from and prepend it to the view.
If this attribute is set, the URL of the :ref:`controller route <reference/controllers>` is
fetched and the returned content is displayed above the view. The JSON response from the
controller must contain an `html` key.
If the HTML contains a `<link>` tag for a stylesheet, it is removed from its original location
and appended to the `<head>` section.
To interact with the backend, use `<a type="action">` tags. For more details, refer to the
documentation of the `_onActionClicked` method in `AbstractController
<{GITHUB_PATH}/addons/web/static/src/js/views/abstract_controller.js>`_.
Only views extending `AbstractView` and `AbstractController`, such as
:ref:`reference/view_architectures/form`, :ref:`reference/view_architectures/kanban`, and
:ref:`reference/view_architectures/list`, can use this attribute.
.. example::
.. code-block:: xml
<tree banner_route="/module_name/hello" />
.. code-block:: python
class MyController(odoo.http.Controller):
@http.route('/module_name/hello', auth='user', type='json')
def hello(self):
return {
'html': """
<div>
<link href="/module_name/static/src/css/banner.css"
rel="stylesheet">
<h1>hello, world</h1>
</div> """
}
:requirement: Optional
:type: path_
:default: `''`
.. _`path`: https://en.wikipedia.org/wiki/Path_(computing)

View File

@ -0,0 +1,8 @@
.. attribute:: create
:noindex:
Disable/enable record creation on the view.
:requirement: Optional
:type: bool
:default: `True`

View File

@ -0,0 +1,9 @@
.. attribute:: default_group_by
:noindex:
The name of the field on which the records should be grouped by default if no grouping is
specified via the action or the current :ref:`search <reference/view_architectures/search>`.
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,18 @@
.. attribute:: default_order
:noindex:
A comma-separated list of fields names that overrides the ordering defined on the model through
the :attr:`~odoo.models.BaseModel._order` attribute.
To inverse the sorting order of a field, postfix it with `desc`, separated by a space.
.. example::
.. code-block:: xml
<tree default_order="sequence,name desc">
...
</tree>
:requirement: Optional
:type: str
:default: `''`

View File

@ -0,0 +1,8 @@
.. attribute:: delete
:noindex:
Disable/enable record deletion on the view through the :guilabel:`Action` dropdown.
:requirement: Optional
:type: bool
:default: `True`

View File

@ -0,0 +1,8 @@
.. attribute:: edit
:noindex:
Disable/enable record edition on the view.
:requirement: Optional
:type: bool
:default: `True`

View File

@ -0,0 +1,16 @@
.. attribute:: sample
:noindex:
Whether the view should be populated with a set of sample records if none are found for the
current model.
These fake records have heuristics for certain field names/models. For example, a field
`display_name` on the model `res.users` will be populated with sample people names, while an
`email` field will be in the form `firstname.lastname@sample.demo`.
The user is unable to interact with these data, and they will be discarded as soon as an action
is performed (record created, column added, etc.).
:requirement: Optional
:type: bool
:default: `False`

View File

@ -0,0 +1,9 @@
.. attribute:: string
:noindex:
The view title. It is displayed only if you open an action that has no name and whose target is
`new` (opening a dialog).
:requirement: Optional
:type: str
:default: `''`

View File

@ -1,35 +1,26 @@
============
View Records
View records
============
Views are what define how records should be displayed to end-users. They are specified in XML which
means that they can be edited independently from the models that they represent. They are flexible
and allow a high level of customization of the screens that they control. There exist various types
of views. Each of them represents a mode of visualization: *form*, *list*, *kanban*, etc.
.. todo:: Build doc of ir_ui_view.py ?
Views are what define how records should be displayed to end-users. They are specified in XML and
stored as records themselves, meaning they can be edited independently from the models that they
represent. They are flexible and allow a high level of customization of the screens that they
control. There exist various :ref:`types of views <reference/view_records/types>`. Each represents a
visualization mode: *form*, *list*, *kanban*, etc.
.. _reference/view_records/structure:
Generic structure
=================
Basic views generally share the common structure defined below. Placeholders are denoted in all
caps.
Basic views generally share the common minimal structure defined below. Placeholders are denoted in
all caps.
.. code-block:: xml
<record id="ADDON.MODEL_view_TYPE" model="ir.ui.view">
<field name="name">NAME</field>
<field name="model">MODEL</field>
<!--
<field name="groups_id" eval="GROUPS"/>
<field name="priority">PRIORITY</field>
-->
<!--
<field name="inherit_id" ref="REFERENCE"/>
<field name="mode">PRIMARY</field>
-->
<field name="arch" type="xml">
<VIEW_TYPE>
<views/>
@ -42,302 +33,338 @@ caps.
View types
==========
- :ref:`Form <reference/view_architecture/form>` ->
display and edit the data from a single record
- :ref:`List <reference/view_architecture/list>` ->
view and edit multiple records
- :ref:`Search <reference/view_architecture/search>` ->
apply filters and perform searches (the result are displayed in the current view list, kanban...)
- :ref:`Kanban <reference/view_architecture/kanban>` ->
displays records as "cards" configurable as a small template
- :ref:`Qweb <reference/view_architecture/qweb>` ->
templating of reporting, website...
- :ref:`Graph <reference/view_architecture/graph>` ->
visualize aggregations over a number of records or record groups
- :ref:`Pivot <reference/view_architecture/pivot>` ->
display aggregations as a `pivot table`_
- :ref:`Calendar <reference/view_architecture/calendar>` ->
display records as events in a daily, weekly, monthly or yearly calendar
:ref:`Form <reference/view_architectures/form>`
Display and edit the data from a single record.
:ref:`List <reference/view_architectures/list>`
View and edit multiple records.
:ref:`Search <reference/view_architectures/search>`
Apply filters and perform searches. The results are displayed in the current list, kanban... view.
:ref:`Kanban <reference/view_architectures/kanban>`
Display records as "cards", configurable as a small template.
:ref:`Qweb <reference/view_architectures/qweb>`
Templating of reporting, website...
:ref:`Graph <reference/view_architectures/graph>`
Visualize aggregations over a number of records or record groups.
:ref:`Pivot <reference/view_architectures/pivot>`
Display aggregations as a `pivot table <https://en.wikipedia.org/wiki/Pivot_table>`_.
:ref:`Calendar <reference/view_architectures/calendar>`
Display records as events in a daily, weekly, monthly, or yearly calendar.
:ref:`Cohort <reference/view_architectures/cohort>` |enterprise|
Display and understand the way some data changes over a period of time.
:ref:`Gantt <reference/view_architectures/gantt>` |enterprise|
Display records as a Gantt chart.
:ref:`Grid <reference/view_architectures/grid>` |enterprise|
Display computed information in numerical cells; are hardly configurable.
:ref:`Map <reference/view_architectures/map>` |enterprise|
Display records on a map, and the routes between them.
.. raw:: html
.. |enterprise| raw:: html
<span class="badge" style="background-color:#AD5E99">Enterprise feature</span>
- :ref:`Cohort <reference/view_architecture/cohort>` ->
display and understand the way some data changes over a period of time
- :ref:`Gantt <reference/view_architecture/gantt>` ->
display records as a Gantt charts (for scheduling)
- :ref:`Grid <reference/view_architecture/grid>` ->
display computed information in numerical cells are hardly configurable
- :ref:`Map <reference/view_architecture/map>` ->
display records on a map and the routes between them
<span class="badge" style="background-color:#714B67">Enterprise feature</span>
.. _reference/view_records/fields:
Fields
======
View objects expose a number of fields. They are optional unless specified otherwise.
View records expose a number of fields.
:name:
:class:`~odoo.fields.Char`
.. autoclass:: odoo.addons.base.models.ir_ui_view.View()
Only useful as a mnemonic/description of the view when looking for one in a list of some sort.
Most Odoo view names start with the name of the addon and end with the type of view being discussed.
.. attribute:: name
:model:
:class:`~odoo.fields.Char` (mandatory)
Only useful as a mnemonic/description of the view when looking for one in a list of some sort.
Most Odoo view names start with the name of the addon and end with the type of view being
discussed.
The model linked to the view, if applicable.
:requirement: Optional
:type: :class:`~odoo.fields.Char`
:arch:
:class:`~odoo.fields.Text`
.. attribute:: model
The description of the view layout depending on :doc:`view type <view_architecture>`
The model linked to the view, if applicable.
:groups_id:
:class:`~odoo.fields.Many2many` -> :class:`~odoo.addons.base.models.res_users.Groups`
:requirement: Mandatory
:type: :class:`~odoo.fields.Char`
The groups allowed to use/access the current view.
.. attribute:: arch
If the view extends an existing view, the extension will only be applied
for a given user if the user has access to the provided ``groups_id``.
The description of the view layout depending on the :doc:`view type <view_architectures>`.
:priority:
:class:`~odoo.fields.Integer`
:requirement: Optional
:type: :class:`~odoo.fields.Text`
When a view is requested by ``model`` and ``type``, the view matching the
model and the type, with the lowest priority will be returned (it is the
default view).
.. attribute:: groups_id
It also defines the order of views application during :ref:`view
inheritance <reference/view_records/inheritance>`. When a view is requested
by ``id``, if its mode is not ``primary`` its *closest* parent with ``mode``
``primary`` is matched.
The groups allowed to use/access the current view.
:inherit_id:
:class:`~odoo.fields.Many2one`
If the view extends an existing view, the extension will be applied only for a given user, if
that user has access to the provided `groups_id`.
Reference to the parent view on which the inheritance will be applied. It
value is uset by default. Specify the parent using the ``ref`` attribute as
`ref="ADDON.MODEL_parent_view_TYPE"`. The addon name (separate by dot) is
not necessary if the inheritance is done on a record of the same module.
:requirement: Optional
:type: :class:`~odoo.fields.Many2many` -> :class:`~odoo.addons.base.models.res_users.Groups`
See :ref:`inheritance <reference/view_records/inheritance>` information
.. attribute:: priority
:mode:
:class:`~odoo.fields.Selection`: ``extension`` / ``primary``
When requesting a view by specifying the `model` and `type`, the matching view with the lowest
priority is returned (it is the default view).
Only applies if this view inherits from an other one (inherit_id is not False/Null).
It also defines the order of views application during :ref:`view resolution
<reference/view_records/inheritance/resolution>`. When a view is requested by `id` and its
mode is not `primary`, its *closest* parent with `mode` = `primary` is matched.
**extension** (default)
if this view is requested the closest primary view is looked up (via inherit_id),
then all views inheriting from it with this view's model are applied
**primary**
the closest primary view is fully resolved (even if it uses a different model than
this one), then this view's inheritance specs (<xpath/>) are applied, and the result
is used as if it were this view's actual arch.
:requirement: Optional
:type: :class:`~odoo.fields.Integer`
An example of where you would want to override ``mode`` while using
``inherit_id`` is delegation inheritance.
In that case your derived model will be separate from its parent and views
matching with one won't match with the other. Suppose you inherit from a view
associated with the parent model and want to customize the derived view to
show data from the derived model. The ``mode`` of the derived view needs to
be set to ``primary``, because it's the base (and maybe only) view for that
derived model. Otherwise the :ref:`view matching <reference/view_records/inheritance/view-matching>`
rules won't apply.
.. attribute:: inherit_id
See :ref:`inheritance <reference/view_records/inheritance>` information
Reference to the parent view on which the :ref:`inheritance
<reference/view_records/inheritance>` will be applied. Its value is used by default. Specify
the parent using the `ref` attribute with :code:`ref="ADDON.MODEL_parent_view_TYPE"`.
.. note:: The current context and user access rights may also impact the view abilities.
The addon name (before the dot) is not necessary if the inheritance is done on a record of the
same module.
See :ref:`reference/view_records/inheritance` for more information.
:requirement: Optional
:type: :class:`~odoo.fields.Many2one`
.. attribute:: mode
Only applies if this view inherits from an other one (`inherit_id` is set).
.. attribute:: extension
If the view is requested, the closest primary view is looked up (via `inherit_id`). Then,
all views inheriting from it with this view's model are applied.
.. attribute:: primary
The closest primary view is fully resolved (even if it uses a different model than the
current one). Then, the view's :ref:`inheritance specs
<reference/view_records/inheritance/specs>` are applied, and the result is used as if it
were this view's actual arch.
A case in which one would want to override `mode` while using `inherit_id` is delegation
inheritance. In that case, your derived model is separated from its parent, and views
matching with one won't match with the other. Assuming one inherits from a view associated
with the parent model and wants to customize the derived view to show data from the derived
model, the `mode` of the derived view needs to be set to `primary` because it is the base (and
maybe only) view for that derived model. Otherwise, the :ref:`view matching
<reference/view_records/inheritance/resolution>` rules won't apply.
See :ref:`reference/view_records/inheritance` for more information.
:requirement: Optional
:type: :class:`~odoo.fields.Selection`: `extension` / `primary`
:default: `extension`
.. note::
The current context and user access rights may also impact the view abilities.
.. _reference/view_records/inheritance:
Inheritance
===========
Inheritance allows you to customize delivered views. This makes it possible, for example,
to add content according to the modules installed, or to deliver different displays
according to the action.
Inheritance allows for customizing delivered views. It makes it possible, for example, to add
content as modules are installed, or to deliver different displays according to the action.
Inherit views generally share the common structure defined below. Placeholders are
denoted in all caps. This synthetic view will update a node targeted by an xpath, and
an other targeted by his name and attributes.
The two following :ref:`view fields <reference/view_records/fields>` `inherit_id` and
`mode` are used to specify inherited views.
Inherit views generally share the common structure defined below. Placeholders are denoted in all
caps. This synthetic view will update a node targeted by an XPath, and another targeted by its name
and attributes.
.. code-block:: xml
<record id="ADDON.MODEL_view_TYPE" model="ir.ui.view">
<field name="model">MODEL</field>
<field name="inherit_id" ref="VIEW_REFERENCE"/>
<!--
<field name="mode">PRIMARY</field>
-->
<field name="arch" type="xml">
<xpath expr="XPATH" position="inside">
CONTENT
</xpath>
<NODE ATTRIBUTES="VALUES" position="replace">
<CONTENT/>
</NODE>
</field>
</record>
<record id="ADDON.MODEL_view_TYPE" model="ir.ui.view">
<field name="model">MODEL</field>
<field name="inherit_id" ref="VIEW_REFERENCE"/>
<field name="mode">MODE</field>
<field name="arch" type="xml">
<xpath expr="XPATH" position="POSITION">
<CONTENT/>
</xpath>
<NODE ATTRIBUTES="VALUES" position="POSITION">
<CONTENT/>
</NODE>
</field>
</record>
.. _reference/view_records/inheritance/view-matching:
The `inherit_id` and `mode` fields determine the :ref:`view resolution
<reference/view_records/inheritance/resolution>`. The `xpath` or `NODE` elements indicate the
:ref:`inheritance specs <reference/view_records/inheritance/specs>`. The `expr` and `position`
attributes specify the :ref:`inheritance position <reference/view_records/inheritance/position>`.
.. _reference/view_records/inheritance/resolution:
View resolution
---------------
Resolution generates the final ``arch`` for a requested/matched ``primary``
view:
Resolution generates the final `arch` for a requested/matched `primary` view as follow:
#. if the view has a parent, the parent is fully resolved then the current
view's inheritance specs are applied
#. if the view has no parent, its ``arch`` is used as-is
#. the current view's children with mode ``extension`` are looked up and their
inheritance specs are applied depth-first (a child view is applied, then
its children, then its siblings)
#. if the view has a parent, the parent is fully resolved, then the current view's inheritance specs
are applied;
#. if the view has no parent, its `arch` is used as-is;
#. the current view's children with mode `extension` are looked up, and their inheritance specs are
applied depth-first (a child view is applied, then its children, then its siblings).
The inheritance is applied according to ``inherit_id``. If several view
record inherit the same view, the order is determined by the ``priority``.
The inheritance is applied according to the `inherit_id` field. If several view records inherit the
same view, the order is determined by the `priority`.
The result of applying children views yields the final ``arch``
The result of applying children views yields the final `arch`.
.. todo:: NOTE on fields_view_get and link to ORM ?
.. _reference/view_records/inheritance/specs:
Inheritance specs
-----------------
Inheritance specs are comprised of an element locator, to match
the inherited element in the parent view, and children element that
will be used to modify the inherited element.
Inheritance specs are applied sequentially and are comprised of:
There are three types of element locators for matching a target element:
#. an element locator to match the inherited element in the parent view;
#. children element to modify the inherited element.
* An ``xpath`` element with an ``expr`` attribute. ``expr`` is an XPath_
expression\ [#hasclass]_ applied to the current ``arch``, the first node
it finds is the match
* a ``field`` element with a ``name`` attribute, matches the first ``field``
with the same ``name``. All other attributes are ignored during matching
* any other element: the first element with the same name and identical
attributes (ignoring ``position`` and ``version`` attributes) is matched
There are three types of element locators:
.. code-block:: xml
- An `xpath` element with an `expr` attribute. `expr` is an `XPath
<https://en.wikipedia.org/wiki/XPath>`_ expression\ [#hasclass]_ applied to the current `arch`,
matching the first node it finds;
- A `field` element with a `name` attribute, matching the first field with the same `name`.
<xpath expr="page[@name='pg']/group[@name='gp']/field" position="inside">
<field name="description"/>
</xpath>
.. note::
All other attributes are ignored.
<div name="name" position="replace">
<field name="name2"/>
</div>
- Any other element, matching the first element with the same `name` and identical attributes.
The view's specs are applied sequentially.
.. note::
The attributes `position` and `version` are ignored.
.. [#hasclass] an extension function is added for simpler matching in QWeb
views: ``hasclass(*classes)`` matches if the context node has
all the specified classes
.. [#hasclass] An extension function is added for simpler matching in QWeb views:
`hasclass(*classes)` matches if the context node has all the specified classes.
.. example::
.. code-block:: xml
<xpath expr="page[@name='pg']/group[@name='gp']/field" position="inside">
<field name="description"/>
</xpath>
<div name="name" position="replace">
<field name="name2"/>
</div>
.. _reference/view_records/inheritance/position:
Inheritance position
--------------------
The inheritance spec may have an optional ``position`` attribute specifying
how the matched node should be altered. By default the value is ``inside``.
The inheritance specs accept an optional `position` attribute, defaulting to `inside`, that
specifies how the matched node should be modified.
:inside:
the content of the inheritance spec is appended to the matched node
.. attribute:: inside
.. code-block:: xml
The content of the inheritance spec is appended to the matched node.
<notebook position="inside">
<page string="New feature">
...
</page>
</notebook>
.. example::
:after:
the content of the inheritance spec is added to the matched node's
parent, after the matched node
.. code-block:: xml
.. code-block:: xml
<notebook position="inside">
<page string="New feature">
...
</page>
</notebook>
<xpath expr="//field[@name='x_field']" position="after">
<field name="x_other_field"/>
</xpath>
.. attribute:: after
:before:
the content of the inheritance spec is added to the matched node's
parent, before the matched node
The content of the inheritance spec is appended to the matched node's parent after the matched
node.
.. code-block:: xml
.. example::
<field name=x_field" position="before">
<field name="x_other_field"/>
</field>
.. code-block:: xml
:replace:
the content of the inheritance spec replaces the matched node.
Any text node containing only ``$0`` within the contents of the spec will
be replaced by a complete copy of the matched node, effectively wrapping
the matched node.
<xpath expr="//field[@name='x_field']" position="after">
<field name="x_other_field"/>
</xpath>
.. code-block:: xml
.. attribute:: before
<xpath expr="//field[@name='x_field']" position="replace">
<div class="wrapper">
$0
</div>
</xpath>
The content of the inheritance spec is appended to the matched node's parent before the matched
node.
:attributes:
the content of the inheritance spec should be ``attribute`` elements
with a ``name`` attribute and an optional body:
.. example::
* if the ``attribute`` element has a body, a new attribute named
after its ``name`` is created on the matched node with the
``attribute`` element's text as value
* if the ``attribute`` element has no body, the attribute named after
its ``name`` is removed from the matched node. If no such attribute
exists, an error is raised
* if the ``attribute`` element has an ``add`` attribute, a ``remove`` attribute, or both, the
value of the matched node's attribute named after ``name`` is recomputed to include the
value(s) of ``add`` (separated by ``separator``) and delete the value(s) of ``remove``
(separated by ``separator``). If ``separator`` is not provided, ``,`` is used instead.
.. code-block:: xml
.. code-block:: xml
<field name=x_field" position="before">
<field name="x_other_field"/>
</field>
<field name="x_field" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="class" add="mt-1 mb-1" remove="mt-2 mb-2" separator=" "/>
</field>
.. attribute:: replace
:move:
can be used as a direct child of a inheritance spec
with a ``inside``, ``replace``, ``after`` or ``before`` ``position`` attribute
to move a node.
The content of the inheritance spec replaces the matched node. Any text node containing only `$0`
within the contents of the spec is replaced by a copy of the matched node, effectively wrapping
the matched node.
.. code-block:: xml
.. example::
<xpath expr="//@target" position="after">
<xpath expr="//@node" position="move"/>
</xpath>
.. code-block:: xml
<field name="target_field" position="after">
<field name="my_field" position="move"/>
</field>
<xpath expr="//field[@name='x_field']" position="replace">
<div class="wrapper">
$0
</div>
</xpath>
Model Commons
.. attribute:: attributes
The content of the inheritance spec should be made of only `attribute` elements, each with a
`name` attribute and an optional body.
- If the `attribute` element has a body, a new attributed named after its `name` is added to the
matched node with the `attribute` element's text as value.
- If the `attribute` element has no body, the attribute named after its `name` is removed from the
matched node.
- If the `attribute` element has an `add` attribute, a `remove` attribute, or both, the value of
the matched node's attribute named after `name` is recomputed to account for the value(s) of
`add`, `remove`, and an optional `separator` attribute defaulting to `,`. `add` includes its
value(s), separated by `separator`. `remove` removes its value(s), separated by `separator`.
.. example::
.. code-block:: xml
<field name="x_field" position="attributes">
<attribute name="invisible">True</attribute>
<attribute name="class" add="mt-1 mb-1" remove="mt-2 mb-2" separator=" "/>
</field>
.. attribute:: move
The attribute `position="move"` is set on the content of the inheritance spec to specify how nodes
are moved relatively to the inheritance spec's element locator, on which the attribute `position`
must also be set, with values `inside`, `replace`, `after`, or `before`.
.. example::
.. code-block:: xml
<xpath expr="//@target" position="after">
<xpath expr="//@node" position="move"/>
</xpath>
<field name="target_field" position="after">
<field name="my_field" position="move"/>
</field>
.. _reference/view_records/model_commons:
Model commons
=============
.. currentmodule:: odoo.addons.base.models.ir_ui_view
.. automethod:: Model.get_views
.. automethod:: Model.get_view
.. autoclass:: odoo.addons.base.models.ir_ui_view.View()
:noindex:
.. _pivot table: https://en.wikipedia.org/wiki/Pivot_table
.. _XPath: https://en.wikipedia.org/wiki/XPath
.. _path: https://en.wikipedia.org/wiki/Path_(computing)
.. _boolean: https://docs.python.org/3/library/stdtypes.html#boolean-values
.. automethod:: Model.get_views
.. automethod:: Model.get_view

View File

@ -56,13 +56,13 @@ Business objects
Declared as Python classes, these resources are automatically persisted
by Odoo based on their configuration
:doc:`Object views <../reference/user_interface/view_architecture>`
:doc:`Object views <../reference/user_interface/view_architectures>`
Definition of business objects UI display
:ref:`Data files <reference/data>`
XML or CSV files declaring the model metadata :
* :doc:`views <../reference/user_interface/view_architecture>` or :ref:`reports
* :doc:`views <../reference/user_interface/view_architectures>` or :ref:`reports
<reference/reports>`,
* configuration data (modules parametrization, :ref:`security rules <reference/security>`),
* demonstration data
@ -1289,7 +1289,7 @@ A report is a combination two elements:
the *report* contextual menu rather than the *action* one. There is no
technical difference but putting elements in the right place helps users.
* A standard :ref:`QWeb view <reference/view_architecture/qweb>` for the actual report:
* A standard :ref:`QWeb view <reference/view_architectures/qweb>` for the actual report:
.. code-block:: xml

View File

@ -64,13 +64,13 @@ An Odoo module **can** contain a number of elements:
these classes are automatically mapped to database columns thanks to the
:abbr:`ORM (Object-Relational Mapping)` layer.
:doc:`Object views <../../reference/user_interface/view_architecture>`
:doc:`Object views <../../reference/user_interface/view_architectures>`
Define UI display
:ref:`Data files <reference/data>`
XML or CSV files declaring the model data:
* :doc:`views <../../reference/user_interface/view_architecture>` or
* :doc:`views <../../reference/user_interface/view_architectures>` or
:ref:`reports <reference/reports>`,
* configuration data (modules parametrization, :ref:`security rules <reference/security>`),
* demonstration data

View File

@ -23,7 +23,7 @@ List
====
**Reference**: the documentation related to this topic can be found in
:ref:`reference/view_architecture/list`.
:ref:`reference/view_architectures/list`.
.. note::
@ -72,7 +72,7 @@ Form
====
**Reference**: the documentation related to this topic can be found in
:ref:`reference/view_architecture/form`.
:ref:`reference/view_architectures/form`.
.. note::
@ -134,7 +134,7 @@ Search
======
**Reference**: the documentation related to this topic can be found in
:ref:`reference/view_architecture/search`.
:ref:`reference/view_architectures/search`.
.. note::
@ -155,7 +155,7 @@ Search
Search views are slightly different from the list and form views since they don't display
*content*. Although they apply to a specific model, they are used to filter
other views' content (generally aggregated views such as
:ref:`reference/view_architecture/list`). Beyond the difference in use case, they are
:ref:`reference/view_architectures/list`). Beyond the difference in use case, they are
defined the same way.
Their root element is ``<search>``. The most basic version of this view simply

View File

@ -17,7 +17,7 @@ read the reference documentation for a more complete overview.
**Reference**: the documentation related to this chapter can be found in
:doc:`../../reference/user_interface/view_records` and
:doc:`../../reference/user_interface/view_architecture`.
:doc:`../../reference/user_interface/view_architectures`.
Inline Views
============
@ -272,7 +272,7 @@ behavior customizations, we can add the ``options`` attribute to several field w
In :ref:`tutorials/getting_started/06_firstui`, we saw that reserved fields were used for
specific behaviors. For example, the ``active`` field is used to automatically filter out
inactive records. We added the ``state`` as a reserved field as well. It's now time to use it!
A ``state`` field is used in combination with a ``invisible`` attribute in the view to display
A ``state`` field can be used in combination with an ``invisible`` attribute in the view to display
buttons conditionally.
.. exercise:: Add conditional display of buttons.
@ -283,17 +283,17 @@ buttons conditionally.
Tip: do not hesitate to search for ``invisible=`` in the Odoo XML files for some examples.
More generally, it is possible to make a field ``invisible``, ``readonly`` or ``required`` based
on the value of other fields. Note that ``invisible`` can also be appliedto other elements of
on the value of other fields. Note that ``invisible`` can also be applied to other elements of
the view such as ``button`` or ``group``.
``invisible``, ``readonly`` or ``required`` can have ``True``, ``False`` or a domain as value.
The domain gives the condition in which the property applies. For example:
`invisible`, `readonly` and `required` can have any Python expression as value. The expression
gives the condition in which the property applies. For example:
.. code-block:: xml
<form>
<field name="description" invisible="not is_partner"/>
<field name="is_partner" invisible="1"/>
<field name="is_partner" invisible="True"/>
</form>
This means that the ``description`` field is invisible when ``is_partner`` is ``False``. It is
@ -386,7 +386,7 @@ Search
------
**Reference**: the documentation related to this section can be found in
:ref:`reference/view_architecture/search` and :ref:`reference/view_architecture/search/defaults`.
:ref:`reference/view_architectures/search` and :ref:`reference/view_architectures/search/defaults`.
.. note::

View File

@ -25,7 +25,7 @@ Concrete Example: A Kanban View
===============================
**Reference**: the documentation related to this topic can be found in
:ref:`reference/view_architecture/kanban`.
:ref:`reference/view_architectures/kanban`.
.. note::
@ -111,7 +111,8 @@ it is possible to add it outside of the ``<templates>`` element.
Refer to the **Goal** of the section for a visual example.
Let's give the final touch to our view: the properties must be grouped by type by default. You
might want to have a look at the various options described in :ref:`reference/view_architecture/kanban`.
might want to have a look at the various options described in
:ref:`reference/view_architectures/kanban`.
.. exercise:: Add default grouping.

View File

@ -1,3 +1,4 @@
# developer/reference
developer/reference/backend/views.rst developer/reference/user_interface/view_records.rst
developer/reference/user_interface/view_architecture.rst developer/reference/user_interface/view_architectures.rst