Skip to Content

Stored Computed Fields in Odoo: The Complete Guide

Understand how stored computed fields work in Odoo, when to use them, and how to create them with Python or Odoo Studio
March 6, 2026 by
Stored Computed Fields in Odoo: The Complete Guide
Dasolo
| No comments yet

Introduction


If you have spent time working with Odoo, you have probably encountered fields that calculate their value automatically. A stored computed field takes this one step further: it calculates the value and saves it directly in the database.


This distinction matters more than it might seem at first. A field that only computes on the fly cannot be searched, filtered, grouped, or exported efficiently. A stored computed field can. It behaves like a regular database column while still being driven by logic you define.


This guide covers everything you need to know about stored computed fields in Odoo: how they work inside the Odoo data model, how to create them using Odoo Studio or Python, real business use cases, and the most common mistakes to avoid.

What is a Stored Computed Field in Odoo


In the Odoo ORM, every field on a model holds a piece of data. Most fields store what the user enters manually. A computed field is different: its value is generated by a Python function rather than entered by a user.


A stored computed field is simply a computed field with store=True. When its dependencies change, Odoo runs the compute function and writes the result into the database column. The value is then available just like any other field.


In Python, the basic pattern looks like this:

total_amount = fields.Float(
    string='Total Amount',
    compute='_compute_total_amount',
    store=True,
)

@api.depends('quantity', 'unit_price')
def _compute_total_amount(self):
    for record in self:
        record.total_amount = record.quantity * record.unit_price

The store=True parameter is what separates a stored computed field from a regular computed field. Without it, the value is recalculated every time the field is read but never persisted in the database.


In the Odoo interface, a stored computed field looks exactly like any other field. Users see it on forms, list views, and reports. They can filter by it, group records using it, and include it in exports. There is no visual indicator that the value is computed rather than entered.


Stored vs Non-Stored Computed Fields

Understanding this difference is essential for any Odoo development work:

  • Non-stored computed field: Calculated on the fly when read. Cannot be used in filters, search, or group-by. Lighter on storage but not available for database queries.
  • Stored computed field: Calculated when dependencies change and saved to the database. Searchable, filterable, exportable. Takes up space in the database like any regular column.

The choice between the two is not about which is better in general. It depends on what you need the field for. If you only display it on a single form, non-stored is fine. If you need to filter, sort, or aggregate by it, use stored.

How the Field Works


When you define a stored computed field in Odoo, the ORM sets up automatic recomputation triggers based on the fields listed in the @api.depends() decorator.


Whenever any of those dependent fields change on a record, Odoo marks that record as needing recomputation. The compute method runs, and the result is written back to the database column for that field.


The Recomputation Lifecycle

Here is what happens step by step:

  1. A user or automated process changes a field that is listed in @api.depends().
  2. Odoo detects the change and identifies all records that depend on this field.
  3. The compute method is called for those records.
  4. The computed value is written to the database column.
  5. The field is now available for search, filter, and export with the updated value.

In most cases, this recomputation happens immediately within the same transaction. For large batch operations, Odoo may defer some recomputations and process them in the background.


Dependencies Across Related Models

The @api.depends() decorator supports dotted paths for accessing fields on related models. For example:


@api.depends('partner_id.country_id.name')
def _compute_country_name(self):
    for record in self:
        record.country_name = record.partner_id.country_id.name or ''

In this case, Odoo tracks changes on partner_id, country_id, and name across models. If the country name changes on a partner, all related records are automatically recomputed. This is one of the most powerful aspects of the Odoo framework.


Database Impact

Because the field is stored, Odoo creates a real column in the PostgreSQL database table. This means the field participates in SQL queries directly. Searches and filters on stored computed fields are fast and efficient, just like searches on regular fields.

Business Use Cases


Stored computed fields show up in all areas of Odoo. Here are five practical examples from real business workflows.


1. Sales: Margin Percentage on Order Lines

A sales team wants to see the margin percentage on each sale order line without opening a calculator. A stored computed field takes the unit price and the cost price, calculates the margin, and stores it on the line. The sales manager can then filter orders by margin percentage, find unprofitable lines instantly, and group by margin bands in pivot views.


2. CRM: Days Without Activity on a Lead

A stored computed field on the CRM lead model can track how many days have passed since the last scheduled activity. Pair this with a scheduled action that triggers recomputation every morning, and your sales team can filter leads by inactivity threshold. No manual follow-up tracking required.


3. Inventory: Net Available Quantity

For products with complex stock rules, a stored computed field can hold a pre-calculated value such as on-hand quantity minus reserved quantity. Because the value is stored, product managers can sort and filter the product list by availability without Odoo running complex stock calculations live for every row on screen.


4. Accounting: Count of Overdue Invoices per Customer

On the customer model, a stored computed field can count how many invoices are currently overdue. When the accounting team opens the contacts list, they can sort customers by overdue invoice count in one click. This is only possible because the count is stored in the database rather than computed on the fly for each row.


5. Manufacturing: Total Estimated Work Duration

In a Bill of Materials, a stored computed field can sum the estimated duration across all work center operations attached to the BOM. Production planners can then filter and sort BOMs by total work time, which is useful for capacity planning and scheduling. Every time an operation is added or modified, the total updates automatically.

Creating or Customizing the Field


There are two main ways to create stored computed fields in Odoo: using Odoo Studio for simple cases, or writing Python code in a custom module for full control.


Using Odoo Studio

Odoo Studio lets you add computed fields without writing any code. When you create a new field of type Integer, Float, or Monetary in Studio, you can enable a formula option that accepts a Python-like expression. Studio handles the dependency tracking behind the scenes.


Studio-computed fields are a good fit when the logic is a simple arithmetic expression between fields on the same record. They are easy to set up and require no development environment. However, they have real limits. If your logic involves related model fields, conditional branches, or aggregation across child records, Studio will not be enough. You will need a custom module.


This is an important distinction when planning your Odoo customization: Studio is fast for straightforward cases, but Python gives you full flexibility when the logic gets complex.


Using a Custom Python Module

For anything beyond basic formulas, you define the field in Python inside a custom Odoo module. Here is a concrete example that adds a margin percentage field to sale order lines:


from odoo import models, fields, api

class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    x_margin_pct = fields.Float(
        string='Margin %',
        compute='_compute_margin_pct',
        store=True,
        digits=(5, 2),
    )

    @api.depends('price_unit', 'purchase_price')
    def _compute_margin_pct(self):
        for line in self:
            if line.price_unit:
                line.x_margin_pct = (
                    (line.price_unit - line.purchase_price) / line.price_unit
                ) * 100
            else:
                line.x_margin_pct = 0.0

When this module is installed, Odoo creates the x_margin_pct column in the database, runs the compute method for all existing records, and begins tracking changes to price_unit and purchase_price from that point on.


The field prefix x_ is the convention for custom fields in Odoo to avoid conflicts with core fields. This is standard practice in Odoo development.


Making a Stored Computed Field Editable

By default, computed fields are read-only. If you want users to be able to override the computed value manually, you can define an inverse method alongside your compute method. The inverse method runs when a user writes directly to the field and can update the source fields accordingly. This pattern is useful for fields where the calculated value is a good default but sometimes needs a manual override.


Odoo Studio Fields and the XML-RPC API

For teams managing Odoo database fields through the XML-RPC API, you can create standard fields via the ir.model.fields model. However, for stored computed fields with custom Python logic, the compute method itself must live in server-side code. The API approach works well for provisioning simple fields as part of automated deployments, but the logic behind a computed field always requires a custom module installed on the server.

Best Practices


Here are the practices that experienced Odoo consultants follow when working with stored computed fields.


Declare All Dependencies Precisely

The @api.depends() decorator must list every field your compute method reads. If you forget one, the field will not update when that dependency changes. Go through your compute method line by line and make sure every field access is listed in the decorator.


Keep Compute Methods Fast

Your compute method runs on every record that is affected by a dependency change. In a busy Odoo instance, this can mean thousands of records at once. Avoid database queries inside compute methods when possible. If you need to access related data, use the fields that are already loaded rather than running additional searches.


Only Use store=True When You Need It

Stored fields consume database space and trigger write operations on every recomputation. If you only need to display the field on a form view and never filter or group by it, a non-stored computed field is the lighter option. Make this decision deliberately rather than defaulting to stored for everything.


Handle Edge Cases in the Compute Method

Always account for empty or missing values inside your compute method. Division by zero, missing related records, and null values are common causes of silent errors in computed fields. Add explicit checks and set safe default values when the normal computation cannot proceed.


Plan for Initial Recomputation on Large Tables

When you install a module that adds a new stored computed field, Odoo recomputes it for every existing record in the table. On a table with hundreds of thousands of rows, this can take a significant amount of time. Test your migration in a staging environment first and plan for potential downtime or background processing when deploying to production.


Avoid Circular Dependencies

If field A depends on field B and field B depends on field A, Odoo will raise an error when the module loads. Design your computed field dependencies to flow in one direction only.

Common Pitfalls


Forgetting store=True

This is the single most common mistake. The field displays correctly on the form view, so everything looks fine during testing. Then someone tries to add it as a filter or include it in a report, and it does not work. Before writing any compute logic, decide upfront whether you need the field to be searchable. If yes, add store=True from the start.


Missing a Dependency in @api.depends

If your compute method reads partner_id.country_id but your decorator only lists partner_id, the field will not update when the country changes on the partner record. Trace the full path of every field access in your method and list each step explicitly in the decorator.


Silent Errors in the Compute Method

If your compute method raises an exception for a record, Odoo silently skips the recomputation for that record and keeps the previous stored value. The error may appear in server logs but nothing is shown to the user. This can lead to stale or incorrect values that are hard to trace. Always test your compute method against records that have missing or unusual data.


Performance Degradation on Large Datasets

A compute method that runs fine during development can become a serious bottleneck in production if the table grows to tens of thousands of records. Pay attention to how many database queries your compute method triggers per record. A single extra query per record multiplied by ten thousand records is ten thousand queries for a single save operation.


Using sudo() Inside Compute Methods

Calling sudo() inside a compute method to bypass access rights is a security risk. If the computed value exposes data that the current user should not see, returning it through a compute method defeats Odoo's permission model. Use sudo() inside compute methods only when you have deliberately thought through the security implications.


Expecting Immediate Recomputation in All Contexts

In most interactive operations, recomputation is synchronous. But during batch imports, background jobs, or certain ORM operations with context flags, Odoo may defer recomputation. Do not build business logic that assumes the stored value is always up to date at the exact moment a record is written. Verify behavior in the specific context where your field will be used.

Conclusion


Stored computed fields are one of the most useful tools available when building or extending Odoo. They let you automate calculations, keep your data consistent, and make records searchable and exportable without any manual work from your users.


The key points to remember:

  • Use store=True when you need the field to be searchable, filterable, or exportable.
  • Always declare all dependencies in @api.depends(), including cross-model paths.
  • Keep compute methods fast and handle edge cases explicitly.
  • For simple formulas, Odoo Studio is a quick option. For anything more complex, write Python.
  • Plan for initial recomputation when deploying to production on large tables.

Whether you are building a new custom module, extending an existing Odoo model, or exploring Odoo field types for the first time, stored computed fields are worth understanding deeply. They sit at the intersection of the Odoo ORM, the database layer, and your business logic.


Need Help With Your Odoo Implementation?

Dasolo helps companies implement, customize and optimize Odoo across a wide range of business needs. Whether you need to add computed fields to your data model, build reports driven by calculated values, or take your Odoo development further, our team has the experience to help.


Reach out to us if you need support with your Odoo project. We are happy to talk through your use case and find the right approach for your business.

Stored Computed Fields in Odoo: The Complete Guide
Dasolo March 6, 2026
Share this post
Sign in to leave a comment