Skip to content

Computed Fields Explained

What Is a Computed Field?

A computed field is a field whose value is calculated automatically based on other fields. Think of it like an Excel formula: Total = Qty * Price. When you change the source fields, the computed field updates automatically!

Common Computed Fields You Use Every Day

FieldModelHow It's Calculated
amount_totalsale.orderSum of all order lines + taxes
price_subtotalsale.order.linequantity × unit price (with discounts)
display_nameres.partnerCombines name + company info
agehr.employeeToday's date - birthday
qty_availableproduct.productSum of all stock quantities
delivery_statussale.orderChecks if all shipments are done
amount_dueaccount.moveTotal - Amount Paid

The Five Configurations of Computed Fields

ConfigurationStored?Editable?Can Filter/Group?When to Use
Computed, Not StoredNoNoNoDynamic values (age, days remaining)
Computed, StoredYesNoYesCalculated values for reporting (totals)
Computed, Stored, EditableYesYes (overwrite)YesDefault value user can override
Computed with InverseOptionalYes (bidirectional)If storedTwo-way binding
Computed with PrecomputeYesOptionalYesCompute BEFORE record creation (Odoo 16+)

Key Behaviors to Remember

  • Default store: Computed fields are store=False by default
  • Default readonly: Computed fields are readonly UNLESS they have an inverse
  • Default copy: Computed fields are NOT copied on duplicate, unless stored AND not readonly
  • Precompute: Only works on stored fields - computes value BEFORE record creation (faster)
  • @api.depends: Required for stored computed fields to know when to recalculate

Real Examples in Odoo

WhereFieldConfigurationWhy?
Sales OrderPricelistComputed, Stored, Editable, PrecomputeDefault from customer, user can change
Sales OrderCurrencyComputed, Stored, Editable, PrecomputeDefault from pricelist, editable
Event TrackTrack DateComputed, Inverse, StoredEdit track date → updates event timing
Link TrackerShort URL CodeComputed, Inverse, EditableAuto-generated code, but customizable

The @api.depends Decorator - What Triggers Recalculation?

For stored computed fields, @api.depends tells Odoo when to recalculate:

python
@api.depends('price_unit', 'quantity')
def _compute_subtotal(self):
    for line in self:
        line.price_subtotal = line.quantity * line.price_unit
Dependency SyntaxMeaning
@api.depends('price_unit', 'quantity')Recalculate when price or quantity changes
@api.depends('order_line.price_subtotal')Recalculate when any order line subtotal changes
@api.depends('partner_id.country_id')Recalculate when the customer's country changes

The Dependency Trap

If a field is used in the calculation but missing from @api.depends, the result won't update automatically!

Example:

  • @api.depends('partner_id.country_id') watches partner_id and country_id
  • ✓ Change the customer → Field updates
  • ✓ Change the customer's country → Field updates
  • ✗ Change the customer's city → Field does NOT update (city isn't watched)

Context-Dependent Fields - Same Product, Different Values

Some computed fields show different values depending on context:

The "Quantity Available" Mystery

Location"Laptop" qty_available
Warehouse A50 units
Warehouse B30 units
Product form (total)80 units

This is because qty_available is a context-dependent computed field!

How Context Works

When you open a product from different places, Odoo passes different context:

  • From Warehouse A screen → {'warehouse': 'WH-A'}
  • From Company X → {'company': 'Company X'}
  • From a specific date report → {'date': '2024-01-15'}

The computed field uses this context to show the relevant value.

Context-Dependent Fields Cannot Be Stored

These fields are NEVER stored because:

  • The value changes based on who's viewing and from where
  • You can't store 50 different values for 50 warehouses in one column

This is why you can't filter or group by "Quantity Available" - it's always calculated fresh.

Editable Computed Fields (Inverse)

Some computed fields let you edit them, and the change flows back to the source:

FieldWhat Happens When You Edit
Margin %Edit margin → price updates to match
Total with TaxEdit total → quantity adjusts
Track DateEdit date → event timing updates

This is called an inverse - the field works in both directions.

How to Recognize Editable Computed Fields

  • The field appears editable (not grayed out)
  • You can type in it, and other fields change automatically
  • Common in pricing, quantities, and percentage calculations

Business Scenario: When to Store Computed Fields

ScenarioStore?Reason
Invoice total amountYesNeed to group invoices by amount in reports
Days until deadlineNoChanges every day, would need constant recalculation
Profit margin %YesWant to filter "orders with margin > 20%"
Full address (combined)NoJust for display, don't need to search by it
Order statusYesWant to filter/group orders by status

Troubleshooting Guide

ProblemLikely CauseSolution
Field shows 0 or emptySource fields are emptyCheck if required source fields have values
Field doesn't update after changeChanged field not in dependsTry saving the record first
Field shows wrong valueStale cached dataRefresh page, clear browser cache
Different users see different valuesContext-dependent fieldCheck if users have different company/warehouse settings
Can't filter/group by the fieldField is not storedAsk developer to add store=True
Field is very slow to loadHeavy computationDeveloper may need to optimize or store it

When to Ask Developer for Changes

Request: "Please store this computed field"

Ask for store=True when:

  • You need to filter or group by the field in list views
  • The field is slow to load because calculation is complex
  • You need the field in reports that query the database directly
  • You want to export the field to Excel with correct values

Request: "Please add X to the depends list"

Ask for additional dependencies when:

  • Changing a field doesn't trigger the expected recalculation
  • You have to manually save/refresh to see updated values

Code Reference (For Developers)

python
# Basic computed field
total = fields.Float(
    compute='_compute_total',
    store=True,  # Save to database
)

@api.depends('quantity', 'price_unit')
def _compute_total(self):
    for record in self:
        record.total = record.quantity * record.price_unit

# Editable computed field with inverse
margin_percent = fields.Float(
    compute='_compute_margin',
    inverse='_inverse_margin',
    store=True,
    readonly=False,
)

@api.depends('cost', 'price')
def _compute_margin(self):
    for record in self:
        if record.price:
            record.margin_percent = (record.price - record.cost) / record.price * 100

def _inverse_margin(self):
    for record in self:
        if record.margin_percent and record.cost:
            record.price = record.cost / (1 - record.margin_percent / 100)

Knowledge Check

Q1: Can't Group By a computed field?

Answer: The field is not stored

Only stored fields exist in the database for SQL grouping. Ask developer to add store=True.

Q2: Computed field requires save to update?

Answer: Missing dependency

The @api.depends decorator is likely missing the field you just changed. Report to developer.

Q3: How to make a computed field editable?

Answer: Add an inverse method

An inverse method allows writing values back to the source fields, enabling two-way binding.

Q4: Why do two users see different qty_available values?

Answer: Context-dependent field

qty_available is calculated based on the user's current warehouse/company context. This is normal behavior.

Q5: A computed field is slow. What can be done?

Answer: Store it or optimize the calculation

Stored computed fields only calculate when source data changes. Non-stored fields calculate every time you view them.