Odoo Meta Programming

December 22, 2025 by
Odoo Meta Programming
Fazri Muhammad Yazid
| No comments yet

Odoo meta programming refers to the mechanisms by which models, fields, methods, and behaviors are constructed, merged, and modified at load time, not at runtime in the traditional Python sense.
What looks like ordinary Python classes is, in reality, a model definition language processed by Odoo’s registry and ORM engine.


1. Model Classes Are Not Instantiated Normally

In standard Python, a class defines how objects are instantiated.
In Odoo, a model class is parsed, registered, and merged into the registry.

class SaleOrder(models.Model):
    _name = 'sale.order'

This class is never instantiated directly.
Odoo reads the class body, extracts metadata, and builds a runtime model dynamically.


2. _name and _inherit Are Meta Instructions

These attributes are not configuration values; they are directives to the model loader.

Create a new model

_name = 'custom.model'

Extend an existing model

_inherit = 'sale.order'

Multiple inheritance (mixin-style)

_inherit = ['sale.order', 'mail.thread']


Odoo merges:

  • fields
  • methods
  • constraints
  • metadata

into a single runtime model, regardless of how many Python classes define it.


3. Method Resolution Is Registry-Based, Not Class-Based

Python’s MRO (Method Resolution Order) is secondary.
Odoo resolves methods after all modules are loaded, based on:

  • module dependency order
  • inheritance chains
  • override definitions
def action_confirm(self):
    res = super().action_confirm()
    self.your_custom_function()
    return res

super() does not mean “parent class” in a simple sense.
It means “previous method version in the registry chain”.


4. Fields Are Collected Declaratively

Fields are not attributes on instances.
They are descriptors collected during class parsing.

amount_total = fields.Monetary(string='Amount Total')
approved_by = fields.Many2one('res.users', string='Approved By')

At load time, Odoo:

  • registers the field
  • attaches it to the model schema
  • links compute, inverse, and search logic
  • decides storage behavior

No field exists until the registry is built.


5. Decorators Modify the Model Graph

Decorators like @api.depends do not wrap functions in the Python sense.
They annotate metadata used later by the ORM.

@api.depends('line_ids.price_subtotal')
def _compute_amount_total(self):
    for record in self:
        record.amount_total = sum(record.line_ids.mapped('price_subtotal'))

Odoo extracts:

  • dependency graph
  • recomputation triggers
  • store vs non-store behavior

The decorator participates in graph construction, not execution flow.


6. Constraints and SQL Rules Are Meta-Level Declarations

_sql_constraints = [
    ('uniq_code', 'unique(code)', 'Code must be unique')
]

This is not runtime validation logic.
It instructs Odoo to:

  • generate SQL constraints
  • apply them during module installation or upgrade

The Python class acts as a schema definition, not business logic.


7. Views and XML Participate in Meta Programming

XML files are not static UI definitions.
They are instructions to mutate existing views.

<xpath expr="//field[@name='partner_id']" position="after">
    <field name="custom_field"/>
</xpath>

At load time:

  • views are parsed
  • inheritance trees are resolved
  • final XML is generated

The result is a synthesized view, not the original file.

Odoo Meta Programming
Fazri Muhammad Yazid December 22, 2025
Share this post
Archive
Sign in to leave a comment