In Odoo, computed fields are designed to automatically generate values based on other fields rather than storing static data. This approach is particularly useful when the value of a field should always reflect a calculation, for example, computing the total price by multiplying a unit price by the quantity:
Total = Unit Price × Quantity
This eliminates the need for manual entry and ensures data consistency.
Stored vs Non-Stored Computed Fields
In Odoo, computed fields are typically recalculated each time they are accessed, as their values are not saved in the database by default. To make these fields searchable or filterable, you have two options. One is to store the computed value in the database by setting store=True, which also enhances performance. The other is to implement a custom search method using the search= parameter, allowing for tailored search behavior even if the field isn’t stored.
Example: Filtering Expired Sales Orders
Let’s look at a practical example: filtering sales orders whose validity date has passed. We'll create a Boolean field called is_expired that returns True if the order's validity date is earlier than today. Since we want to filter based on this field, we'll also implement a custom search method.
Python Code
from odoo import fields, models , api
class SaleOrder(models.Model):
_inherit = 'sale.order'
is_expired = fields.Boolean(string="Expired", compute='_compute_is_expired', search='_search_is_expired')
@api.depends('validity_date')
def _compute_is_expired(self):
today = fields.Date.today()
for rec in self:
rec.is_expired = False
if rec.validity_date < today:
rec.is_expired = True
def _search_is_expired(self, operator, value):
today = fields.Date.today()
records = self.env['sale.order'].search([('validity_date', '<', today)])
return [('id', 'in', records.ids)]
In this setup, the _compute_is_expired method checks whether the validity_date has passed and sets the field accordingly. Since the field is not stored in the database, we define a custom search method, _search_is_expired, which enables filtering by evaluating a domain that returns all expired records. Although the operator and value arguments are required by the Odoo framework, they're not used in this basic implementation.
Adding the Filter in the XML Search View
Next, we extend the search view to add a filter for the is_expired field. This allows users to easily filter and view expired sales orders from the user interface:
<record id="view_sales_order_filter" model="ir.ui.view">
<field name="name">sales.order.search.view.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
<field name="mode">primary</field>
<field name="priority">32</field>
<field name="arch" type="xml">
<xpath expr="//filter[@name='my_sale_orders_filter']" position="after">
<filter name="is_expired" string="Expired" domain="[(is_expired, '=', True)]"/>
</xpath>
</field>
</record>

Similarly, it's possible to add a search functionality not just for boolean fields, but also for computed fields across other field types.
Conclusion
Computed fields bring automation and real-time accuracy to Odoo models. However, making them searchable requires additional steps:
* Use store=True if the computed value should be saved and indexed.
* Define a custom search method if the value is computed dynamically and doesn’t need to be stored.
By combining both the compute and search methods, along with proper XML view configuration, you can create powerful, user-friendly filters based on dynamic business logic.
To read more about How to Add a Search Filter for Computed Fields in Odoo 17, refer to our blog How to Add a Search Filter for Computed Fields in Odoo 17.