Skip to Content

Foundations of Odoo Development

14 May 2025 by
Foundations of Odoo Development
Uday Sankar K
| 1 Comment

Foundations of Odoo Development 



introduction 

Odoo is a full-fledged, open-source ERP software designed to meet diverse business needs with its modular architecture. One of its greatest strengths is its flexibility—when a situation demands a new feature or functionality, you don’t need to modify the existing codebase. Instead, Odoo allows you to extend and customize effortlessly by inheriting code.

Odoo employs a modular, multi-tier architecture, heavily influenced by the Model-View-Controller (MVC) design pattern.

At its core, Odoo’s framework is built around a client-server model, with a PostgreSQL database back end, a Python-based application layer, and a web-based frontend powered by JavaScript and XML. 


Modules

Each module encapsulates specific business functionalities (e.g., sales, inventory, accounting). This modularity is key to Odoo's flexibility and scalability.At their core, Odoo modules are simply directories within the Odoo addons path. These directories contain Python files (.py), XML files (.xml), and potentially other static assets.


my_module/

├── __init__.py               # Initializes Python modules

├── __manifest__.py           # Module metadata and dependencies

├── controllers/              # Web controllers (HTTP routes)

│   └── __init__.py           # Initializes controllers module

├── models/                   # Business models (ORM classes)

│   ├── __init__.py           # Initializes models module

│   └── my_model.py           # Custom business logic

├── views/                    # XML UI definitions (forms, lists, menus)

│   └── my_model_views.xml    # Views for the model

├── security/                 # Access control and security rules

│   ├── ir.model.access.csv   # Model access rights

│   └── security.xml          # Record rules and groups

├── data/                     # Demo or initial data (XML/CSV)

│   └── my_model_data.xml     # Preloaded records

├── static/                   # Web assets (JS, CSS, images)

│   └── description/          # Module icon and description for App list

│       └── icon.png          # Icon shown in the Odoo app store

└── tests/                    # Unit or functional tests

    └── test_my_model.py      # Python test cases


The __manifest__.py is Mission Control: This crucial file acts as the module's descriptor.It uniquely identifies your module within the Odoo ecosystem.  It contains essential information like the module's name, version, author, dependencies, website, description, and the list of data files to be loaded. It's the first file Odoo reads to understand your module


Syntax and Structure:


The __manifest__.py file is a standard Python dictionary. Here's a breakdown of the common keys and their values:         

{

    'name': '',                # Module name shown in Odoo

 'version': '',             # Module version

    'summary': '',             # Short description in apps list

    'description': '',         # Long description of the module

    'author': '',              # Author of the module

    'website': '',             # Website of the author/company

    'license': '',             # License type (e.g. LGPL-3)

    'category': '',            # App category in Odoo store

    'depends': [],             # List of dependent modules

    'data': [],                # Data files to load (views, security, etc.)

    'demo': [],                # Demo data for testing or demo purposes

    'qweb': [],                # QWeb templates for frontend

    'installable': True,       # Whether module can be installed

    'application': False,      # Marks it as an application (visible in app list)

    'auto_install': False,     # Auto-install if dependencies are met

}

ex:

{

    'name': 'My Awesome Module',

    'version': '1.0',

    'summary': 'A short and catchy description of my module.',

    'description': """

        A more detailed explanation of what this module does.

        It can span multiple lines.

    """,

    'author': 'Your Name or Company Name',

    'website': 'https://www.yourwebsite.com',

    'license': 'LGPL-3', # Or other appropriate license

    'category': 'Specific Industry/Category',

    'depends': ['sale', 'mail'],

    'data': [

        'security/ir.model.access.csv',

        'views/my_model_view.xml',

        'views/my_other_view.xml',

        'data/initial_data.xml',

        'wizards/my_wizard_view.xml',

    ],

    'demo': [

        'demo/demo_data.xml',

    ],

    'qweb': [

        'static/src/xml/my_template.xml',

    ],

    'installable': True,

    'application': False,

    'auto_install': False,

}



Models

Models in Odoo are classes that represent database tables using the Odoo ORM (Object-Relational Mapping). They define how data is stored, validated, and manipulated.
Defining a model using the models.Model class.To define a new model in Odoo, you create a Python file (e.g., models/my_model.py) and define a class that inherits from models.Model. Odoo automatically handles the underlying database table creation and management based on your model definition.

from odoo import models, fields, api

class MyModel(models.Model):

    _name = 'my.model'  # Required: A unique technical name for the model

    _description = 'Description of My Model' # Optional: A human-readable description

_name: This is a mandatory attribute. It's the unique technical identifier for your model within Odoo's system. It's typically written in lowercase with dots separating logical parts (e.g., library.book, sale.order.line). Odoo uses this name int

_description: This is an optional attribute that provides a human-readable description of your model. It's often used in the Odoo interface and documentation.


Fields

Creating fields to store data.

Fields define the attributes of your model and correspond to columns in the database table.

1. Char

  • Use: Stores short text (strings).
  • Syntax:
    fields.Char(string='Label', required=True, help='Tooltip')
    
  • Example:
    name = fields.Char(string="Name", required=True, help="Product Name")
    

2. Boolean

  • Use: Stores True or False (checkbox).
  • Syntax:
    fields.Boolean(string='Label', default=False)
    
  • Example:
    active = fields.Boolean(string="Active", default=True)
    

3. Date

  • Use: Stores calendar dates.
  • Syntax:
    fields.Date(string='Label', help='Tooltip')
    
  • Example:
    start_date = fields.Date(string="Start Date")
    

4. Datetime

  • Use: Stores both date and time.
  • Syntax:
    fields.Datetime(string='Label')
    
  • Example:
    create_date = fields.Datetime(string="Created On")
    

5. Float

  • Use: Stores decimal numbers.
  • Syntax:
    fields.Float(string='Label', digits=(precision, scale))
    
  • Example:
    discount = fields.Float(string="Discount", digits=(10, 2))
    

6. Integer

  • Use: Stores whole numbers.
  • Syntax:
    fields.Integer(string='Label')
    
  • Example:
    quantity = fields.Integer(string="Quantity")
    

7. Html

  • Use: Stores HTML content (rich text editor).
  • Syntax:
    fields.Html(string='Label')
    
  • Example:
    notes = fields.Html(string="Internal Notes")
    

8. Binary

  • Use: Stores binary files (images, PDFs, etc.).
  • Syntax:
    fields.Binary(string='Label')
    
  • Example:
    image = fields.Binary(string="Company Logo")
    

9. Selection

  • Use: Dropdown with predefined options.
  • Syntax:
    fields.Selection([('key1', 'Label 1'), ('key2', 'Label 2')], default='key1')
    
  • Example:
    state = fields.Selection([
      ('draft', 'Draft'),
      ('confirmed', 'Confirmed'),
      ('done', 'Done')
    ], default='draft', string="Status")
    
🔸 Relational Field Types

10. Many2one

  • Use: Links current model to a single record in another model (foreign key).
  • Syntax:
    fields.Many2one('target.model', string='Label')
    
  • Example:
    partner_id = fields.Many2one('res.partner', string="Customer")
    

11. One2many

  • Use: Links one record to many in another model (inverse of Many2one).
  • Syntax:
    fields.One2many('target.model', 'inverse_field', string='Label')
    
  • Example:
    order_line_ids = fields.One2many('sale.order.line', 'order_id', string="Order Lines")
    

12. Many2many

  • Use: Links many records to many (symmetric relationship).
  • Syntax:
    fields.Many2many('target.model', string='Label')
    
  • Example:
    tag_ids = fields.Many2many('project.tags', string="Tags")
    



 Odoo Field Parameters

These parameters help control how fields behave in Odoo models, including their display, validation, default values, dynamic computation, and more.

1. string

Description: UI label for the field (defaults to field name if not specified).

Example:

string="Customer Name"

2. required

Description: Makes the field mandatory in the UI.

Possible Values: True / False

Example:

required=True

3. readonly

Description: Makes the field uneditable in the UI.

Possible Values: True / False

Example:

readonly=True

4. default

Description: Sets a default value for new records (can be static or dynamic).

Example:

default=0

default=lambda self: self.env.user.name

5. help

Description: Adds a tooltip to guide users.

Example:

help="Enter the full customer name"

6. store

Description: Stores the value of a computed field in the database (enables search/filtering).

Possible Values: True / False

Example:

store=True

7. compute

Description: References the method used to compute the field's value dynamically.

Example:

compute="_compute_total"

8. invisible

Description: Hides the field from the UI (used in views).

Possible Values: True / False

Example:

invisible=True

9. translate

Description: Allows the field to be translated into multiple languages.

Possible Values: True / False

Example:

translate=True

10. states

Description: Dynamically changes field behavior based on the record's state.

Usage: A dictionary mapping states to a list of (attribute, value) pairs.

Example:

states={
   'done': [('readonly', True)],
   'draft': [('invisible', True)]
}
 

Odoo Model Methods

Model methods define the behavior of your data and allow you to perform actions on records. Odoo provides several built-in methods for common data manipulation tasks. You can also define your own custom methods to implement specific business logic.


Using Built-in Methods in Odoo

Odoo allows us to define our own methods and also provides several built-in methods that are commonly used for interacting with models and records. These built-in methods are already defined in Odoo’s base classes and can be inherited and customized as needed.

You can access any model in Odoo using the syntax:

model = self.env['model.name']

For example:

partner = self.env['res.partner'].create({'name': 'John Doe'})

This means you’re calling the built-in create method on the res.partner model.

 Common Built-in Methods in Odoo

Method

Purpose

Syntax Example Usage Example
create Add new record def create(self, vals): ... self.env['model'].create({'field': 'value'})
read Read fields def read(self, fields=None): ... self.env['model'].read([ids], [fields])
write Update record(s) def write(self, vals): ... record.write({'field': 'new_value'})
unlink Delete record(s) def unlink(self): ... record.unlink()
search Find by domain def search(self, domain): ... self.env['model'].search([('field', '=', value)])
browse Get record by ID def browse(self, ids): ... self.env['model'].browse(id)


Customizing Built-in Methods

These methods can also be overridden to include custom logic. Here’s how you can override the write method:

def write(self, vals):

    # custom logic before update

    result = super().write(vals)

    # custom logic after update

    return result


Similarly, you can override other built-in methods like create, unlink, etc.

Example – Customizing create:

def create(self, vals):

    # custom pre-processing

    record = super().create(vals)

    # custom post-processing

    return record


Understanding This Code:

partner = self.env['res.partner'].create({'name': 'John Doe'})

Breakdown:

  • self.env: Gives access to Odoo’s environment, including models and records.

  • ['res.partner']: Refers to the partner model.

  • create({...}): Calls the built-in create method to create a new partner record with the provided values.

These built-in methods are already written in Odoo’s core framework. When we use them in our custom models, we’re effectively inheriting their functionality. You don’t need to re-implement them unless you want to add or modify behavior. That’s the power of object-oriented inheritance in Odoo.


Custom Method Definition 

In Odoo, your models are defined as Python classes that inherit from Odoo's base model classes (primarily models.Model). Within these classes, you define both your data fields and your custom business logic through methods.

from odoo import models, fields, api

class YourModuleName(models.Model):

    _name = 'your.model.technical.name'

    _description = 'A human-readable description of your model'

    # --- Field Definitions ---

    field_one = fields.Char(string='Field One Label')

    field_two = fields.Integer(string='Field Two Label', default=0)

    # ... more field definitions ...

    # --- Custom Method Definitions ---

    def your_custom_method(self, parameter1, parameter2=None):

        """

        A docstring explaining what this method does.

        :param parameter1: Description of the first parameter.

        :param parameter2: Description of the second parameter (optional).

        :return: What the method returns (if anything).

        """

        # Your custom logic goes here

        print(f"Executing your_custom_method with parameter1: {parameter1}, parameter2: {parameter2}")

        processed_value = parameter1 * 2

        if parameter2 is not None:

            processed_value += parameter2

        return processed_value


    def another_method(self):

        """Another custom method."""

        for record in self: # Iterate through the recordset

            print(f"Processing record with name: {record.field_one}")

            # Perform actions on each record in the self recordset

            record.field_two += 1

            record.write({'field_two': record.field_two})


    self: The first parameter of any instance method in an Odoo model (and Python classes in general) is always self. self refers to the recordset on which the method is called. Even if you call the method on a single record, self will be a recordset of size 1. You use self to access the fields of the records in the recordset and to interact with the Odoo environment (self.env).


Model Inheritance in Odoo

Model inheritance is a powerful feature in Odoo that allows you to extend and customize existing models without modifying the core code

Inheriting Existing Models

This is used when you want to add new fields or methods to an existing model.

Syntax: Inheriting a Model

from odoo import models, fields

class InheritModel(models.Model):

    _inherit = 'model.name'  # Replace with actual model name

    new_field = fields.Char(string="New Field Name")

    def new_method(self):

        # Your custom logic here

        pass

Example: Add a New Field to res.partner

from odoo import models, fields

class PartnerInherit(models.Model):

    _inherit = 'res.partner'

    customer_code = fields.Char(string='Customer Code')


Full Example in a Model

from odoo import models, fields, api


class CustomModel(models.Model):

    _name = 'custom.model'

    _description = 'Example Custom Model'


    name = fields.Char(string="Name", required=True, help="Enter the name")

    active = fields.Boolean(string="Active", default=True)

    start_date = fields.Date(string="Start Date")

    total = fields.Monetary(string="Total", currency_field='currency_id')

    currency_id = fields.Many2one('res.currency', string="Currency")

    partner_id = fields.Many2one('res.partner', string="Customer")

    notes = fields.Html(string="Notes")

    status = fields.Selection([

        ('draft', 'Draft'),

        ('approved', 'Approved'),

        ('done', 'Done')

    ], default='draft', string="Status")




Odoo Model Types

Odoo provides multiple base classes for defining models. The most common ones are:

1. models.Model – Persistent Model

Definition: This is the standard model class in Odoo. Data stored in this model is persistent — it is saved in the database and stays there unless deleted.

Used for: Main business models (e.g., sale.order, res.partner, product.template, etc.).

Syntax:

from odoo import models, fields

class MyModel(models.Model):
    _name = 'my.model'
    name = fields.Char(string='Name')

Features:

  • Data is stored permanently.
  • Can be used in menus, views, and actions.
  • Supports security access rules.

Example:

class LibraryBook(models.Model):
    _name = 'library.book'
    name = fields.Char(string="Title")
    author = fields.Many2one('res.partner', string='Author')

2. models.TransientModel – Temporary Model / Wizard Model

Definition: Used for temporary data, like wizards or popups. Data is automatically deleted after some time (usually after the session ends or a few minutes).

Used for: Wizards, short-lived forms, and temporary user interactions.

Syntax:

from odoo import models, fields

class MyWizard(models.TransientModel):
    _name = 'my.wizard'
    name = fields.Char(string='Temporary Name')

Features:

  • Data is not persisted long-term.
  • Ideal for wizards, assistants, or temporary UI elements.
  • No security rules applied unless specified.
  • Can't be accessed directly like res.partner from the menu.

Example:

class AttendanceWizard(models.TransientModel):
    _name = 'attendance.wizard'
    date_from = fields.Date(string="Start Date")
    date_to = fields.Date(string="End Date")

    def generate_report(self):
        # temporary logic
        return {
            'type': 'ir.actions.act_window',
            'name': 'Report',
            # more return values...
        }

3. models.AbstractModel – Reusable Logic Only (No DB Table)

Definition: Used for shared logic, with no table created in the database.

Used for: Utility functions, common business logic, and mixins.

Syntax:

class MyMixin(models.AbstractModel):
    _name = 'my.mixin'

Features:

  • No actual records are stored.
  • Inherited by other models for common methods or functionality.
  • Can be used as Mixin classes (e.g., mail.thread).

Example:

class TimestampMixin(models.AbstractModel):
    _name = 'timestamp.mixin'

    def get_timestamp(self):
        return fields.Datetime.now()




Odoo Views

Views in Odoo are XML files that define how records of your models are displayed and interacted with in the user interface. They control everything from the layout of forms to the columns in lists and the organization of kanban boards. Understanding views is crucial for crafting a user-friendly and efficient Odoo application.

They support embedding HTML and referencing CSS to create rich, styled, and user-friendly interfaces. The XML structure acts as a wrapper or container for UI components, while HTML tags (like <div>, <span>, <table>) and CSS classes (built-in or custom) provide styling and layout control.

XML (eXtensible Markup Language) is a markup language used to define structured data. It’s similar to HTML but is designed to store and transport data, not display it. In Odoo, XML is used to define views, menus, actions, access rights, and more.

Most Common Odoo XML Tags & Their Purpose

Here is a list of commonly used Odoo XML tags, along with their purpose:

1. <odoo>

  • Purpose: Root tag in all XML files loaded by Odoo.

2. <data>

  • Purpose: Wraps all record definitions and view elements.

3. <record>

  • Purpose: Defines a database record (views, actions, menus, etc.).

4. <field>

  • Purpose: Defines the value of a field in a record or inside form/tree views.

5. <form>, <tree>, <kanban>, <calendar>, <graph>

  • Purpose: UI views that define the type of view structure.

6. <sheet>

  • Purpose: Used inside <form> to wrap fields in a clean layout.

7. <group>

  • Purpose: Groups fields (horizontal or vertical) inside <sheet> or <form>.

8. <notebook>

  • Purpose: Creates tabs inside forms.

9. <page>

  • Purpose: Tab inside <notebook>.

10. <button>

  • Purpose: Adds a button (action, workflow, etc.) inside views.

11. <menuitem>

  • Purpose: Creates menu entries (top and submenus).

12. <act_window>

  • Purpose: Defines an action to open a view.

13. <search>

  • Purpose: Defines a search view.

14. <filter>

  • Purpose: Adds filters to a search view.

15. <xpath>

  • Purpose: Used for view inheritance/modification.

Basic Structure of an Odoo XML File

<odoo>

<data>

     <!-- All your records (views, actions, menus, etc.) go here -->

</data>

</odoo>


Full XML View Definition Example


<odoo>
    <data>
        <!-- Tree View -->
        <record id="model_name_tree" model="ir.ui.view">
            <field name="name">model.name.tree</field>
            <field name="model">model.name</field>
            <field name="arch" type="xml">
                <tree>
                    <field name="name"/>
                    <field name="date"/>
                </tree>
            </field>
        </record>

        <!-- Form View -->
        <record id="model_name_form" model="ir.ui.view">
            <field name="name">model.name.form</field>
            <field name="model">model.name</field>
            <field name="arch" type="xml">
                <form>
                    <sheet>
                        <group>
                            <field name="name"/>
                            <field name="description"/>
                        </group>
                    </sheet>
                </form>
            </field>
        </record>

        <!-- Action -->
        <record id="action_model_name" model="ir.actions.act_window">
            <field name="name">Model Name</field>
            <field name="res_model">model.name</field>
            <field name="view_mode">tree,form</field>
        </record>

        <!-- Menu -->
        <menuitem id="menu_model_root" name="Root Menu"/>
        <menuitem id="menu_model_name" name="Model Name" parent="menu_model_root" action="action_model_name"/>

    </data>
</odoo>

Explanation:

  1. Tree View:
    • This creates a tree view (model_name_tree) for the model.name model, displaying fields name and date.
  2. Form View:
    • Defines a form view (model_name_form) for the same model, with fields name and description inside a group layout within a sheet.
  3. Action:
    • Creates an action (action_model_name) to open the model’s views in tree and form mode when triggered.
  4. Menu:
    • A root menu item (menu_model_root) and a sub-menu item (menu_model_name) are created, which links to the action defined above.

  5. Record:

  •  A <record> tag defines a database record in Odoo, representing elements like views, actions, or menus. Each <record> has a unique id used to reference it in the system. For example, a <record> for an action defines how views (tree, form, etc.) are opened when triggered. It’s essential for creating and modifying key components in Odoo.

6. sheet:

  • The <sheet> tag visually wraps the form content inside a clean, card-style box. It adds padding, proper alignment, and standard UI styling for better presentation. The <sheet> tag is always used inside a <form> to structure and organize the fields effectively.
💡

In Odoo 18, the <tree> tag has been replaced by the <list> tag for defining list views in XML. To update or fix your views, simply change <tree> to <list> in your XML files. All attributes you previously used with <tree> (such as create, delete, editable, default_order, etc.) should now be placed inside the <list> tag, and the structure of the view remains the same


Odoo Widgets

Here's a list of Odoo widgets, along with example code snippets and how you might use them in a GitHub Markdown file.

1. widget="handle"

  • Use: Displays a handle for reordering records in a list view.
  • Code Example:
    <field name="sequence" widget="handle"/>
  • Markdown:
    Use `widget="handle"` to add a drag-and-drop handle for reordering items in a list view. Example:
    
    ```xml
    <field name="sequence" widget="handle"/>
    

2. widget="boolean_toggle"

  • Use: Displays a toggle switch for boolean fields.
  • Code Example:
    <field name="active" widget="boolean_toggle"/>
  • Markdown:
    `widget="boolean_toggle"` provides a user-friendly toggle switch for boolean values.
    
    ```xml
    <field name="active" widget="boolean_toggle"/>

3. widget="domain"

  • Use: Displays a domain editor for filtering records.
  • Code Example:
    <field name="filter_domain" widget="domain"/>
  • Markdown:
    The `widget="domain"` allows users to visually construct complex search filters.
    
    ```xml
    <field name="filter_domain" widget="domain"/>
    

4. widget="code"

  • Use: Displays a code editor for text fields.
  • Code Example:
    <field name="python_code" widget="code" options="{'mode': 'python'}"/>
  • Markdown:
    Use `widget="code"` to provide a syntax-highlighted code editor. You can specify the language mode.
    
    ```xml
    <field name="python_code" widget="code" options="{'mode': 'python'}"/>
    

5. widget="many2many_tags"

  • Use: Displays many2many relationships as tags.
  • Code Example:
    <field name="tag_ids" widget="many2many_tags"/>
  • Markdown:
    `widget="many2many_tags"` shows related records as interactive tags.
    
    ```xml
    <field name="tag_ids" widget="many2many_tags"/>
    

6. widget="statusbar"

  • Use: Displays the status of a record in a visual status bar.

Code Example:
<field name="state" widget="statusbar" statusbar_visible="draft,sent,done"/>

  • Markdown:
    The `widget="statusbar"` gives a clear visual representation of a record's workflow.
    
    ```xml
    <field name="state" widget="statusbar" statusbar_visible="draft,sent,done"/>

7. widget="radio"

  • Use: Displays a radio button group for selection fields.
  • Code Example:
    <field name="selection_field" widget="radio"/>
  • Markdown:
    `widget="radio"` provides a radio button interface for selection fields.
    
    ```xml
    <field name="selection_field" widget="radio"/>
    

8. widget="char"

  • Use: Displays a simple text input field (default behavior, often implicit).
  • Code Example:
    <field name="name" widget="char"/>
  • Markdown:
    `widget="char"` is the standard text input widget.
    
    ```xml
    <field name="name" widget="char"/>
    

9. widget="image"

  • Use: Displays an image field.
  • Code Example:
    <field name="image" widget="image"/>
  • Markdown:
    `widget="image"` renders image fields within the view.
    
    ```xml
    <field name="image" widget="image"/>
    

10. widget="url"

  • Use: Displays a URL as a clickable link.
  • Code Example:
    <field name="website" widget="url"/>
  • Markdown:
    `widget="url"` transforms text into clickable web links.
    
    ```xml
    <field name="website" widget="url"/>

11. widget="phone"

  • Use: Displays a phone number as a clickable link (for calling).
  • Code Example:
    <field name="phone" widget="phone"/>
  • Markdown:
    `widget="phone"` renders phone numbers as clickable links for calling.
    
    ```xml
    <field name="phone" widget="phone"/>
    

12. widget="reference"

  • Use: Displays a reference field (linking to various models).
  • Code Example:
    <field name="related_record" widget="reference"/>
  • Markdown:
    `widget="reference"` shows a field that links to records from different models.
    
    ```xml
    <field name="related_record" widget="reference"/>

13. widget="timezone_mismatch"

  • Use: Displays a warning if the user's timezone differs from the record's timezone.
  • Code Example:
    <field name="date_time" widget="timezone_mismatch"/>
  • Markdown:
    `widget="timezone_mismatch"` warns users about potential timezone discrepancies.
    
    ```xml
    <field name="date_time" widget="timezone_mismatch"/>

14. widget="statinfo"

  • Use: Displays statistical information in a compact format.
  • Code Example:
    <field name="total_sales" widget="statinfo"/>
  • Markdown:
    `widget="statinfo"` presents key metrics in a visually concise way.
    
    ```xml
    <field name="total_sales" widget="statinfo"/>

15. widget="image_url"

  • Use: Displays an image from a URL.
  • Code Example:
    <field name="image_url" widget="image_url"/>
  • Markdown:
    `widget="image_url"` renders images fetched from external URLs.
    
    ```xml
    <field name="image_url" widget="image_url"/>
    
  • 16. widget="many2one_avatar_user `
  • Use: Displays a user avatar based on a many2one field of res.users.
  • Module: sale_management
  • Field Type: Many2one
  • Code Example:
    <field name="user_id" widget="many2one_avatar_user"/>
  • Markdown:
    `widget="many2one_avatar_user"` displays a user's avatar.
    
    ```xml
    <field name="user_id" widget="many2one_avatar_user"/>

17. widget="badge"

  • Use: Displays a badge based on the selection field of state.
  • Module: sale_management
  • Field Type: Selection
  • Code Example:
    <field name="state" widget="badge" options="{'colors': {'draft': 'secondary', 'confirmed': 'primary'}}"/>
  • Markdown:
    `widget="badge"` displays a colored badge based on a selection field.
    
    ```xml
    <field name="state" widget="badge" options="{'colors': {'draft': 'secondary', 'confirmed': 'primary'}}"/>

18. widget="char_emojis" / widget="text_emojis"

  • Use: Allows entering and displaying emojis in char or text fields.
  • Module: mass_mailing
  • Field Type: Char or Text
  • Code Example:
    <field name="description" widget="text_emojis"/>
  • Markdown:
    `widget="char_emojis"` / `widget="text_emojis"` enables emoji input and display.
    
    ```xml
    <field name="description" widget="text_emojis"/>

19. widget="remaining_days"

  • Use: Calculates and displays the remaining days based on a datetime field.
  • Module: purchase
  • Field Type: Datetime
  • Code Example:
    <field name="date_deadline" widget="remaining_days"/>
  • Markdown:
    `widget="remaining_days"` shows the remaining days until a deadline.
    
    ```xml
    <field name="date_deadline" widget="remaining_days"/>

20. widget="Countdown" (Website Widget)

  • Use: A website-specific widget (drag and drop) to create countdown timers.
  • Module: website
  • Markdown:
    `widget="Countdown"` (Website Widget) creates countdown timers on website pages.

21. widget="color_picker"

  • Use: Allows selecting a color via a color picker for an integer field.
  • Module: sale_management
  • Field Type: Integer
  • Code Example:
    <field name="color" widget="color_picker"/>
  • Markdown:
    `widget="color_picker"` provides a color selection tool.
    
    ```xml
    <field name="color" widget="color_picker"/>

22. widget="kanban_activity"

  • Use: Displays activities in a Kanban view, related to a mail.activity object via a one2many field.
  • Module: sale_management
  • Field Type: one2many
  • Code Example:
    <field name="activity_ids" widget="kanban_activity" optional="show"/>
  • Markdown:
    `widget="kanban_activity"` displays activities in a Kanban card.
    
    ```xml
    <field name="activity_ids" widget="kanban_activity" optional="show"/>

23. widget="many2one_avatar_employee"

  • Use: Displays an employee avatar based on a many2one field of hr.employee.
  • Module: hr_expense
  • Field Type: Many2one
  • Code Example:
    <field name="employee_id" widget="many2one_avatar_employee"/>
  • Markdown:
    `widget="many2one_avatar_employee"` displays an employee's avatar.
    
    ```xml
    <field name="employee_id" widget="many2one_avatar_employee"/>

24. widget="product_discount"

  • Use: A specialized widget for displaying and handling product discounts (float field).
  • Module: sale_management
  • Field Type: Float
  • Code Example:
    <field name="discount" widget="product_discount"/>
  • Markdown:
    `widget="product_discount"` handles product discount display.
    
    ```xml
    <field name="discount" widget="product_discount"/>

25. widget="account_resequence_widget"

  • Use: Special widget to re-sequence accounting entries.
  • Module: account
  • Field Type: Text
  • Markdown:
    `widget="account_resequence_widget"` re-sequences accounting entries.

26. widget="grouped_view_widget"

  • Use: Used for grouped views in accounting, especially for invoice grouping.
  • Module: account
  • Field Type: Text
  • Markdown:
    `widget="grouped_view_widget"` is used for grouped accounting views.

27. widget="task_with_hours"

  • Use: Connect to a task in a task management system.
  • Module: hr_timesheet
  • Field Type: many2one
  • Code Example:
    <field name="task_id" widget="task_with_hours"/>
  • Markdown:
    `widget="task_with_hours"` connects to a task with hours.
    
    ```xml
    <field name="task_id" widget="task_with_hours"/>

28. widget="timesheet_uom_no_toggle"

  • Use: Time sheet user management control.
  • Module: project
  • Field Type: Float
  • Markdown:
    `widget="timesheet_uom_no_toggle"` controls timesheet user management.

29. widget="forecast_widget"

  • Use: Forecast values.
  • Module: stock
  • Field Type: Float
  • Markdown:
    `widget="forecast_widget"` displays forecast values.

30. widget="stock_rescheduling_popover"

  • Use: Stock rescheduling information.
  • Module: mrp
  • Field Type: Char
  • Markdown:
    `widget="stock_rescheduling_popover"` displays stock rescheduling info.
Frequently Used Class Styles in Odoo

Here’s a more structured and ordered version of the breakdown for Odoo's commonly used CSS classes:

1. oe_read_only

Use: Makes a field or element read-only, preventing user interaction.

Example:

<field name="field_name" class="oe_read_only"/>
<div class="oe_read_only">This text is read-only.</div>

Markdown:

The oe_read_only class prevents user interaction with a field or element.

2. oe_edit_only

Use: Makes a field or element visible only in edit mode.

Example:

<field name="field_name" class="oe_edit_only"/>
<div class="oe_edit_only">This appears only during editing.</div>

Markdown:

The oe_edit_only class displays an element only when the form is in edit mode.

3. oe_highlight

Use: Visually highlights an element, often used for important information or warnings.

Example:

<field name="field_name" class="oe_highlight"/>
<div class="oe_highlight">This is highlighted.</div>

Markdown:

The oe_highlight class provides a visual highlight to draw attention to an element.

4. oe_inline

Use: Displays an element inline, similar to display: inline;.

Example:

<span class="oe_inline">Inline text</span>
<span class="oe_inline">Another inline text</span>

Markdown:

The oe_inline class renders elements horizontally, side by side.

5. oe_right and oe_left

Use: Aligns elements to the right or left, respectively.

Example:

<div class="oe_right">Right-aligned text</div>
<div class="oe_left">Left-aligned text</div>

Markdown:

The oe_right and oe_left classes control text or element alignment.

6. oe_bold

Use: Applies bold text styling.

Example:

<span class="oe_bold">Bold text</span>

Markdown:

The oe_bold class renders text in bold.

7. oe_italic

Use: Applies italic text styling.

Example:

<span class="oe_italic">Italic text</span>

Markdown:

The oe_italic class renders text in italics.

8. o_form_sheet, o_form_sheet_bg, o_form_label, o_form_input

Use: These classes are part of Odoo's form layout structure, providing consistent styling for forms.

Example:

<div class="o_form_sheet">
	<div class="o_form_sheet_bg">
    	<label for="name" class="o_form_label">Name</label>
    	<input type="text" name="name" class="o_form_input"/>
	</div>
</div>

Markdown:

Odoo's form styling relies on classes like o_form_sheet, o_form_sheet_bg, o_form_label, and o_form_input for consistent layouts.

9. o_list_view and o_list_table

Use: These classes are used to style list views and their tables.

Example:

<tree class="o_list_view">
	<field name="name"/>
</tree>

Markdown:

o_list_view and o_list_table are core classes for styling list views.

10. o_kanban_view and o_kanban_record

Use: These classes are used to style kanban views and individual kanban cards.

Example:

<kanban class="o_kanban_view">
	<templates>
    	<t t-name="kanban-box">
        	<div class="o_kanban_record">
            	<field name="name"/>
        	</div>
    	</t>
	</templates>
</kanban>

Markdown:

o_kanban_view and o_kanban_record are fundamental classes for kanban view styling.

This list provides a well-organized overview of commonly used CSS classes in Odoo, their purposes, and examples of how they’re applied in the code.


Frequently Used T-directives in Odoo XML

Odoo's XML templating engine relies heavily on T-directives (prefixed with t-) for dynamic content generation. Here's a breakdown of commonly used T-directives:

1. t-as

Use: Assigns an alias to the current item within a t-foreach loop.

Example:

<t t-foreach="records" t-as="record">
	<t t-esc="record.name"/>
</t>

Markdown:

t-as creates an alias for the current item in a loop, simplifying access to its properties.

2. t-call

Use: Includes another template within the current template.

Example:

<t t-call="module.template_name"/>

Markdown:

t-call allows you to reuse template snippets, promoting code modularity.

3. t-else

Use: Defines the alternative block to execute when the condition in t-if is false.

Example:

<t t-if="condition">
	...
</t>
<t t-else="">
	...
</t>

Markdown:

t-else provides an alternative execution path for t-if conditions.

4. t-esc

Use: Evaluates an expression and escapes the result for safe HTML output.

Example:

<t t-esc="record.name"/>

Markdown:

t-esc safely displays dynamic content, preventing potential cross-site scripting (XSS) vulnerabilities.

5. t-foreach

Use: Iterates over a collection (e.g., a list or recordset).

Example:

<t t-foreach="records" t-as="record">
	...
</t>

Markdown:

t-foreach loops through a set of items, enabling dynamic content generation for each item.

6. t-if

Use: Conditionally renders a block of content based on a boolean expression.

Example:

<t t-if="record.active">
	...
</t>

Markdown:

t-if allows you to display or hide content based on specific conditions.

7. t-key

Use: Specifies a unique key for an element, particularly useful within t-foreach loops for efficient DOM updates.

Example:

<t t-foreach="records" t-as="record">
	<div t-key="record.id">
    	...
	</div>
</t>

Markdown:

t-key optimizes DOM updates in loops by providing unique identifiers for elements.

8. t-name

Use: Assigns a name to a template, making it reusable via t-call.

Example:

<t t-name="module.template_name">
	...
</t>

Markdown:

t-name defines a named template that can be invoked using t-call.

9. t-out

Use: Evaluates an expression and outputs the result without HTML escaping (use with caution).

Example:

<t t-out="record.html_field"/>

Markdown:

t-out outputs raw HTML, so use it carefully to avoid XSS vulnerabilities.

10. t-set

Use: Assigns a value to a variable within the template scope.

Example:

<t t-set="total" t-value="record.price * record.quantity"/>

Markdown:

t-set creates or modifies variables within the template's context.

11. t-value

Use: Specifies the value to be assigned to a variable using t-set.

Example:

<t t-set="total" t-value="record.price * record.quantity"/>

Markdown:

t-value defines the value that t-set assigns to a variable.

This format preserves your content exactly as requested, while presenting it in a more structured, easy-to-read layout.


View Inheritance and Overriding in Odoo

In Odoo, views control how data from models is displayed to users. These views can be form views, tree views, kanban views, calendar views, etc. When customizing Odoo without breaking the core system or future upgrades, view inheritance is the preferred approach. However, for significant changes, overriding views is an option.

1. View Inheritance in Odoo

Purpose:

View inheritance allows you to modify or extend existing views (such as form, tree, kanban) without directly changing the original source code. This ensures that your customizations remain upgrade-safe and compatible with Odoo’s modular architecture.

Steps to Inherit a View:

  1. Create a New XML File
    Place it inside your module’s views/ directory (e.g., views/sale_order_inherit.xml).
  2. Add to Manifest
    Reference the XML file in your module’s manifest.py:
    'data': [
        'views/sale_order_inherit.xml',
    ],
    
  3. Define the Inherited View
    In the XML file, define the inherited view using the <record> tag. Reference the original view using inherit_id and modify it using XPath.
    Example:
    <odoo>
      <record id="sale_order_form_inherit" model="ir.ui.view">
        <field name="name">sale.order.form.inherit</field>
        <field name="model">sale.order</field>
        <field name="inherit_id" ref="sale.view_order_form"/>
        <field name="arch" type="xml">
          <!-- Add a field after 'partner_id' -->
          <xpath expr="//field[@name='partner_id']" position="after">
            <field name="x_custom_field"/>
          </xpath>
        </field>
      </record>
    </odoo>
    

Key Attributes:

Field Description
inherit_id The XML ID of the original view you're modifying (use ref="" syntax).
arch Contains the XML definition that uses XPath to target specific areas for modification.
xpath Locates the exact node where your content will be inserted.
position Controls where to place your element (e.g., after, before, replace, etc.).

Common XPath + Position Examples:

XPath Expression What it Targets
//field[@name='partner_id'] Field by its name attribute
//group[@string='Delivery'] Group by its label
//notebook/page[@string='Other'] Specific page inside a notebook
//button[@name='action_confirm'] Button by its name attribute
Position Description
after Adds new content after the matched element
before Adds new content before the matched element
replace Replaces the matched element completely
inside Adds content inside the matched element (as a child)
attributes Modifies the attributes (e.g., invisible="1") of the matched tag

Use Cases of View Inheritance:

  • Adding a custom field to a form.
  • Changing labels or visibility of fields.
  • Reorganizing layouts (e.g., moving fields between groups).
  • Adding buttons, tabs, status bars, or widgets.

2. View Overriding in Odoo

Purpose:

When major changes are required and you no longer want to use the default structure, overriding a view allows you to replace the entire view with your own custom version.

Steps to Override a View:

  1. Create a New View
    Define a new view with the same model and type as the original view. Use a higher priority to ensure your view overrides the original one.
  2. Set Higher Priority
    Set the priority of your custom view to a higher value (default is 16). This ensures your view takes precedence over the original view.
  3. Define the New Structure
    Rewrite the view’s XML structure entirely based on your custom requirements.
    Example:
    <odoo>
      <record id="sale_order_form_override" model="ir.ui.view">
        <field name="name">sale.order.form.override</field>
        <field name="model">sale.order</field>
        <field name="priority" eval="20"/>  <!-- Ensure it's higher than original -->
        <field name="arch" type="xml">
          <form>
            <sheet>
              <group>
                <field name="name"/>
                <field name="partner_id"/>
                <field name="x_custom_field"/>
              </group>
            </sheet>
          </form>
        </field>
      </record>
    </odoo>
    

Key Considerations When Overriding a View:

Risk Explanation
Upgrade Fragility Overridden views will not receive updates if the base module changes.
Hard to Maintain You are responsible for maintaining the entire layout and structure.
Not Modular Overriding views is discouraged in modular design and should only be done when absolutely required.

Tools for View Inheritance

XPath Expressions:

  • //field[@name='field_name']: Targets a field by its name attribute.
  • //group[@name='group_name']: Targets a group by its name attribute.
  • //button[@name='action_name']: Targets a button by its name attribute.

Position Attributes:

Attribute Description
after Insert the new element after the matched element.
before Insert the new element before the matched element.
replace Replace the matched element with new content.
inside Append the new element inside the matched element.
attributes Modify the attributes (e.g., invisible="1") of the matched element.


Foundations of Odoo Development
Uday Sankar K 14 May 2025
Share this post
Sign in to leave a comment