Skip to content

OD318 view-mode-without-view

A window action lists a view type its model has no view for.

Category Severity Series Needs the index
Correctness Error all yes

What it reports

A type in the literal view_mode of a window action, a <record> or an <act_window>, that the model cannot give: no indexed module has a primary view of that model and type, and Odoo does not generate one. There is one finding per type. Form, search, list, tree, pivot, kanban and graph are never reported, as Odoo generates those. Any other type, such as gantt, map, hierarchy, cohort or grid, needs a primary view, or a default a module in depends adds, as web_gantt and web_map do. On 9.0, a type that a script of an indexed module adds to the web client's view registry and no indexed view has is the client's own, drawn from a view of another type, so it needs no view either. From 10.0 the client asks the server for the type the action lists, and the action fails without a view of it. A module of unknown series is held to that too.

Activity is one of those, and it also needs the field activity_ids on the model, as the web client searches on it to open the view. Without that field a view does not help, nor does mail in depends. Inherit mail.activity.mixin, with mail in depends: that gives the field and the default view. A field only a module outside depends adds counts, as a view does, and so does one from a delegated parent, by _inherits or delegate=True: a model with a delegate the rule cannot read, or that has an unknown class in its parents, is not reported for the field. Activity is not reported before saas~12.4, where the view takes neither, nor in a module of unknown series, which may run on such a series.

The action is read as Odoo loads it, field by field, through the module and its depends. A <record> that gives only a view_mode, such as one adding gantt to another module's action, is checked against the res_model that action holds. A view_mode a later <record> of the same id replaces is not checked. A module depending on this one does not count here: if it replaces the view_mode, the action is still reported, as a database without that module opens what this one wrote. A demo write does not count for a data value either, as a database may hold no demo data.

Odoo generates a calendar only from the fields it finds. The rule reports calendar when the model has neither the field _date_name names nor date, date_start, x_date or x_date_start. Before saas~19.1 it also needs one of date_stop, date_end, x_date_stop, x_date_end, date_delay, planned_hours, x_date_delay or x_planned_hours. A module of unknown series skips that second check, and a _date_name that is no literal keeps the rule silent. A field an ir.model.fields record adds counts, as OD304 describes. A _date_name only a module outside depends sets counts, as a field from such a module does. One a delegated parent sets does not, as _inherits passes on fields only: set _date_name on the model that the action opens. A delegated parent with an unknown class keeps the rule silent on a generated calendar, as that class may give the field.

Why it matters

The action loads without complaint and fails when a user clicks it: every type of view_mode goes through get_views, so one type without a view breaks the whole action with No default view of type, and a type whose module is missing breaks it in the web client. An activity view on a model without activity_ids fails when it opens, with Invalid field.

A view counts from any indexed module, in depends or not, as a bridge module may add it. A view from a module that is neither in depends nor indexed is reported, because a fresh database fails: add that module to depends and index it, or the rule falls silent as described below. Views created at runtime, such as those of Studio, are not seen.

An extension gives its model no type, as Odoo looks a default view up among primary views alone, so a view that extends another for a different model does not count. Set mode to primary on it, and it does.

A view the rule cannot settle counts. One that may be primary gives its type, and one that may be primary with its type on a parent the rule does not read silences every type of its model. Give the view's parent with ref and its mode as a plain value, and the rule reads it like any other.

A primary view that names its model takes its type from the top of its inheritance, so with a view above it not indexed, it silences every type of the model, whatever its own root says. Index the module of that view, and the rule counts the one type it gives. These silences cover views only: a model without activity_ids is still reported.

The rule stays silent when it cannot see every class of the model: a module whose dependencies include one that is not indexed, such as an Enterprise module, a module that builds model names at runtime, a model that is unknown or outside depends (OD201 and OD202 report those), and a class merged into the model that has a plain Python base or an _inherit no indexed module defines. An update of an action outside the scan, or whose res_model is an eval, and a view_mode that is an eval, are silent as well. An unread data file in scope may hold a view, so it silences every type of the action, but not activity_ids, as a field a data file adds is named x_.

An unknown class on a delegated parent, a plain Python base or an _inherit the rule cannot read, there or on a model that parent inherits, silences the activity_ids and calendar field checks only. Odoo looks a view up by the model's own name, and _inherits passes on fields, so such a parent gives no view type: define the view on the model that the action opens.

An action that names a view is silent for the type of that view, whatever its model, as Odoo takes it as it is. A row of view_ids with a view names the type of the row, and a <kind>_view_ref key in context names that kind. A view_id serves the type of its view alone, as Odoo looks a view up for every other type of view_mode: a list view there leaves gantt reported. A row without a view names none, so Odoo still looks a view up for its type, and a view_ids that clears the field or writes no row names nothing: give the row a view_id.

view_id and context hold what their last write left, as view_mode does, so a later write that clears the view_id or drops the key takes the view away, and an <act_window> clears whichever of the two it does not give. A write takes a view away only when it always loads with the module: one from a module outside depends does not, nor does a demo write for a data value. Name the view in the last write that gives the field.

A row in an ir.actions.act_window.view record of its own counts when its act_window_id gives the XML id of the action, by ref or by eval. One that only a run can tell, such as a search, names no action, so the action stays reported: give the row its action by XML id. A record nested in view_ids counts from saas~15.1 and in a module of unknown series. Earlier series cannot load it, so the action is reported there: write the row in an eval of view_ids, or in a record of its own.

The field activity_ids is still needed, as a named view does not give it to the model. For a view_mode in a data file, a view that only a demo file names does not count, as a database may hold no demo data.

A view the rule cannot reach leaves the type open, and silences every type of the action, but for activity_ids: a view_id that only a run can tell, one whose view is not indexed or has a parent the rule does not read, and an eval of view_ids that may hold a view without giving its view_mode as a literal. Give the view_id by ref and index the module of its view, and the rule counts the one type it gives. The rule does not run what gives a view_id either: one given by a search counts, even if that search would find nothing on a database. A name counts from any indexed module, as a view does.

Example

views/project_task_views.xml
<record id="action_task" model="ir.actions.act_window">
    <field name="name">Tasks</field>
    <field name="res_model">project.task</field>
    <field name="view_mode">list,form,gantt</field>
</record>

project.task has no gantt view, and no module in depends gives a default one.

views/project_task_views.xml
<record id="action_task" model="ir.actions.act_window">
    <field name="name">Tasks</field>
    <field name="res_model">project.task</field>
    <field name="view_mode">list,form</field>
</record>

Suppressing

<!-- odooscan: ignore[OD318] -->

See suppressing a finding.