Odoo Custom Module Development Part 4 - Menus, Actions, and Views

This is the fourth article in the Odoo custom module development series.

In Part 3, we secured our models. In this article, we will make the estate module visible and usable in the Odoo interface.

Without views, actions, and menus, your model exists in the database but users cannot work with it properly.

What we will build

We will add:

  • a top-level Estate menu
  • a menu item for properties
  • a window action
  • a list view
  • a form view
  • a search view

1. Create the XML file for views

Create this file:

estate/views/estate_property_views.xml

2. Add a basic list view

Add this content:

<odoo>
<record id="view_estate_property_list" model="ir.ui.view">
<field name="name">estate.property.list</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<list string="Properties">
<field name="name"/>
<field name="postcode"/>
<field name="expected_price"/>
<field name="selling_price"/>
<field name="bedrooms"/>
<field name="state"/>
</list>
</field>
</record>
</odoo>

This gives a simple record listing for the estate.property model.

3. Add a form view

Extend the same file:

<odoo>
<record id="view_estate_property_list" model="ir.ui.view">
<field name="name">estate.property.list</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<list string="Properties">
<field name="name"/>
<field name="postcode"/>
<field name="expected_price"/>
<field name="selling_price"/>
<field name="bedrooms"/>
<field name="state"/>
</list>
</field>
</record>

<record id="view_estate_property_form" model="ir.ui.view">
<field name="name">estate.property.form</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<form string="Property">
<sheet>
<group>
<group>
<field name="name"/>
<field name="postcode"/>
<field name="date_availability"/>
<field name="expected_price"/>
<field name="selling_price"/>
</group>
<group>
<field name="bedrooms"/>
<field name="living_area"/>
<field name="facades"/>
<field name="garage"/>
<field name="garden"/>
<field name="garden_area"/>
<field name="garden_orientation"/>
<field name="state"/>
<field name="active"/>
</group>
</group>
<notebook>
<page string="Description">
<field name="description"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
</odoo>

The form view is where users will create and edit property records.

4. Add a search view

Search views make filtering and grouping easier.

Add this record inside the same XML file:

<record id="view_estate_property_search" model="ir.ui.view">
<field name="name">estate.property.search</field>
<field name="model">estate.property</field>
<field name="arch" type="xml">
<search string="Search Properties">
<field name="name"/>
<field name="postcode"/>
<field name="state"/>
<filter name="filter_available" string="Available" domain="[('state', '=', 'new')]"/>
<group expand="0" string="Group By">
<filter name="group_by_postcode" string="Postcode" context="{'group_by': 'postcode'}"/>
<filter name="group_by_state" string="State" context="{'group_by': 'state'}"/>
</group>
</search>
</field>
</record>

5. Add an action window

Actions tell Odoo which model and views to open.

Still inside the same file, add:

<record id="action_estate_property" model="ir.actions.act_window">
<field name="name">Properties</field>
<field name="res_model">estate.property</field>
<field name="view_mode">list,form</field>
</record>

6. Add menus

Now create visible menu entries:

<menuitem id="menu_estate_root" name="Estate" sequence="10"/>

<menuitem
id="menu_estate_property"
name="Properties"
parent="menu_estate_root"
action="action_estate_property"
sequence="10"
/>

A complete version of estate_property_views.xml should now include all these records inside one <odoo> block.

7. Load the file in the manifest

Update __manifest__.py:

'data': [
'security/estate_security.xml',
'security/estate_rules.xml',
'security/ir.model.access.csv',
'views/estate_property_views.xml',
],

8. Upgrade the module

Run:

cd ~/odoo-dev/odoo
source .venv/bin/activate
python3 odoo-bin -c ~/odoo-dev/odoo.conf -d odoo19 -u estate --stop-after-init

Then start Odoo normally and refresh the browser.

You should now see the Estate menu with the Properties submenu.

9. Improve the form layout

Odoo forms become easier to use when fields are organized logically.

Practical tips:

  • keep identity and pricing fields near the top
  • place longer content such as descriptions inside notebook pages
  • keep booleans and small numeric fields grouped together
  • do not overload the first version of the form with too many tabs

You can refine the form later with status bars, buttons, and conditional visibility.

10. Add a separate menu for property types

If you created estate.property.type in the previous article, add another action and menu for it.

Example:

<record id="action_estate_property_type" model="ir.actions.act_window">
<field name="name">Property Types</field>
<field name="res_model">estate.property.type</field>
<field name="view_mode">list,form</field>
</record>

<menuitem
id="menu_estate_property_type"
name="Property Types"
parent="menu_estate_root"
action="action_estate_property_type"
sequence="20"
/>

You can also create dedicated list and form views for this model.

11. Common mistakes

The menu appears but clicking it shows an access error

The user likely does not have the correct group or the access CSV is missing permissions.

XML parse error during upgrade

Check for:

  • missing closing tags
  • wrong ref values
  • duplicate XML IDs
  • multiple <odoo> root tags in the same file

The view does not update

You probably changed the XML file but did not upgrade the module.

Final words

Your custom module is now visible in the Odoo interface and users can open property records from menus.

In the next article, we will add model relationships, computed fields, onchange methods, and business logic.

Previous article: Part 3 - Security and Access Rights

Next article: Part 5 - Relations, Computed Fields, and Business Logic

Related posts

Md. Monirul Alom

Md. Monirul Alom

I am a Full Stack Web developer. I love to code, travel, do some volunteer work. Whenever I get time I write for this blog