Skip to content

How Odoo View Architecture Works: Inheritance, Priority, and Resolution

DeployMonkey Team · March 23, 2026 13 min read

View Architecture Overview

Every screen in Odoo is defined by one or more ir.ui.view records. When the web client requests a view, Odoo resolves the base view, applies all inherited view extensions in priority order, and returns the combined XML. Understanding this process is essential for customizing Odoo without breaking existing functionality.

View Types

Odoo supports these view types, each rendered by a different frontend component:

  • form — single record editing
  • list (tree) — tabular record listing
  • kanban — card-based grouped display
  • search — search bar, filters, group by
  • pivot — pivot table for analysis
  • graph — charts (bar, line, pie)
  • calendar — calendar display
  • activity — activity planning view
  • gantt — Gantt chart (Enterprise)
  • map — geographical map (Enterprise)

Base View Definition

<record id="view_ticket_form" model="ir.ui.view">
  <field name="name">support.ticket.form</field>
  <field name="model">support.ticket</field>
  <field name="arch" type="xml">
    <form>
      <header>
        <field name="state" widget="statusbar"/>
      </header>
      <sheet>
        <group>
          <field name="name"/>
          <field name="partner_id"/>
        </group>
      </sheet>
    </form>
  </field>
</record>

View Inheritance

The most powerful concept in Odoo views. Instead of replacing views, you extend them using inherit_id:

<record id="view_ticket_form_inherit" model="ir.ui.view">
  <field name="name">support.ticket.form.inherit.my_module</field>
  <field name="model">support.ticket</field>
  <field name="inherit_id" ref="support.view_ticket_form"/>
  <field name="arch" type="xml">
    <field name="partner_id" position="after">
      <field name="priority"/>
      <field name="user_id"/>
    </field>
  </arch>
</record>

XPath Expressions

Use <xpath> for precise targeting when simple element matching is ambiguous:

<!-- Match by element + attribute -->
<xpath expr="//field[@name='partner_id']" position="after">
  <field name="email"/>
</xpath>

<!-- Match by CSS class -->
<xpath expr="//div[hasclass('oe_title')]" position="inside">
  <h3>Custom Title</h3>
</xpath>

<!-- Match notebook page by name -->
<xpath expr="//page[@name='details']" position="after">
  <page string="Custom Tab" name="custom">
    <field name="custom_field"/>
  </page>
</xpath>

<!-- Match by position in parent -->
<xpath expr="//group[1]" position="inside">
  <field name="new_field"/>
</xpath>

Position Attribute

Controls where the new content goes relative to the matched element:

  • after — insert after the matched element
  • before — insert before the matched element
  • inside — append inside the matched element (at the end)
  • replace — replace the matched element entirely
  • attributes — modify attributes of the matched element
  • move — move the matched element to a new location
<!-- Change attributes -->
<field name="name" position="attributes">
  <attribute name="readonly">state == 'done'</attribute>
  <attribute name="required">True</attribute>
</field>

<!-- Replace element -->
<field name="old_field" position="replace">
  <field name="new_field"/>
</field>

<!-- Remove element (replace with nothing) -->
<field name="unwanted_field" position="replace"/>

View Priority and Resolution

When multiple views exist for the same model and type, Odoo uses these rules:

  1. The view with the lowest priority value (default: 16) becomes the base view
  2. All inherited views are applied in priority order (lowest first)
  3. Within the same priority, views are applied in module dependency order
<record id="view_ticket_form_high_priority" model="ir.ui.view">
  <field name="name">support.ticket.form.priority</field>
  <field name="model">support.ticket</field>
  <field name="priority">5</field>
  <!-- Lower number = higher priority = processed first -->
  <field name="arch" type="xml">
    <form>...</form>
  </field>
</record>

Primary vs Extension Views

Views are either primary (base) or extension (inherited):

  • Primary views: have no inherit_id. They define the base structure.
  • Extension views: have inherit_id. They modify the primary view.

You can create a new primary view that inherits from another primary view. This creates a separate view that starts from the parent but diverges:

<record id="view_ticket_form_alternative" model="ir.ui.view">
  <field name="name">support.ticket.form.alt</field>
  <field name="model">support.ticket</field>
  <field name="inherit_id" ref="support.view_ticket_form"/>
  <field name="mode">primary</field>
  <!-- mode='primary' makes this a standalone view -->
  <field name="arch" type="xml">
    <field name="name" position="replace">
      <field name="display_name"/>
    </field>
  </field>
</record>

Linking Views to Actions

Actions reference views by type or explicitly:

<!-- Automatic: Odoo picks the lowest-priority view per type -->
<record id="action_tickets" model="ir.actions.act_window">
  <field name="res_model">support.ticket</field>
  <field name="view_mode">list,form,kanban</field>
</record>

<!-- Explicit: specify exactly which views to use -->
<record id="action_tickets" model="ir.actions.act_window">
  <field name="res_model">support.ticket</field>
  <field name="view_mode">list,form</field>
  <field name="view_ids" eval="[
    (5, 0, 0),
    (0, 0, {'view_mode': 'list', 'view_id': ref('view_ticket_list')}),
    (0, 0, {'view_mode': 'form', 'view_id': ref('view_ticket_form')}),
  ]"/>
</record>

Debugging View Issues

Common view problems and how to fix them:

  • Field not appearing: Check the xpath expression matches the correct element. Use developer mode to inspect the combined view XML.
  • View inheritance conflict: Two modules modifying the same element. Adjust priority or use more specific xpath.
  • View not loading: Check the module dependency chain. The inheriting module must depend on the module that defines the base view.
  • Wrong view being used: Check view priorities. Use explicit view_ids in the action to force a specific view.