How to Search Product Variants by Attribute Value in Odoo 19
When running a warehouse where products come with attributes, such as T-shirts in various sizes and colors or electronic devices with varying storage capacities, the default Odoo stock inventory view allows filtering by product names, lots, and locations but not by attribute values. This limitation creates a daily friction for warehouse teams. A worker picking items does not search by product name — they search by what makes a variant distinct: the color, the size, the configuration. This complete step by step beginner guide walks through creating a custom Odoo 19 module from scratch that adds attribute-value search capability directly to the stock inventory view.
What You'll Learn:
- How to structure a minimal Odoo 19 module for extending stock.quant
- How to add a computed Many2many field that exposes product attribute values on the quant
- How to write a custom _search method that resolves attribute names to product variants
- How to inherit the stock.quant search view and add a filter_domain for the new field
- How to install the module and test attribute-based searching in warehouse inventory
Understanding the Problem: Why Attribute Search Matters
Odoo 19's product variant system is powerful, but its out-of-the-box search capabilities do not always keep up with how warehouse teams actually think about stock. People working in a warehouse do not search by product name — they search by what makes a variant distinct. A picker needs to find all "Red" T-shirts across multiple product lines, or locate every "128GB" device in inventory.
The default stock.quant search view filters by product name, lot number, and location, but it has no awareness of attribute values. Without a custom module, searching "Red" returns nothing unless a product name happens to contain that word. This forces warehouse teams to navigate through product hierarchies manually, slowing down picking and counting operations.
Attribute-Aware Search
Type "Red", "Large", or "128GB" into the stock inventory search bar and see only matching quants returned instantly, regardless of product name.
Minimal Module Footprint
The module extends only what is necessary — a single computed field and a search view inheritance. No new database tables, no security rules, no complicated dependencies.
No Model Changes Required
The module does not create new models or alter existing database schemas. It uses a non-stored computed field that resolves attribute values at search time without adding database columns.
Reusable Pattern
The same technique of compute + _search + filter_domain works on any Odoo model with product_id or variant relationships, including delivery orders and sales order lines.
What We Are Building
The module named product_attr_search extends stock.quant by adding a simple search feature. Once installed, entering an attribute value such as "Red" or "128GB" in the search box displays only those quants whose product variant carries a matching attribute value.
The module achieves this through three components working together: a computed Many2many field that maps each quant to its variant's attribute values, a custom _search method that resolves user input into product IDs, and an inherited search view that exposes the field for filtering.
product_attr_search/
├── __init__.py
├── __manifest__.py
├── models/
│ ├── __init__.py
│ └── stock_quant.py
└── views/
└── stock_quant_views.xml
Step-by-Step Module Implementation
Step 1: Create the Module Manifest
The manifest tells Odoo what this module is and what it depends on. Only the stock module is needed as a dependency since that is where stock.quant and its search view live.
{
'name': 'Product Attribute Search',
'version': '19.0.1.0.0',
'depends': ['stock'],
'data': [
'views/stock_quant_views.xml',
],
}
Step 2: Extend the stock.quant Model
This is the core of the module. We inherit stock.quant and add a computed Many2many field that represents the attribute values of each quant's product variant, along with a _search method that Odoo calls when the field is used as a search criterion.
from odoo import models, fields, api
class StockQuant(models.Model):
_inherit = 'stock.quant'
product_attribute_value_ids = fields.Many2many(
'product.attribute.value',
string='Attribute Values',
compute='_compute_product_attribute_value_ids',
search='_search_product_attribute_value_ids',
store=False,
)
@api.depends('product_id.product_template_attribute_value_ids')
def _compute_product_attribute_value_ids(self):
for quant in self:
quant.product_attribute_value_ids = quant.product_id.product_template_attribute_value_ids.mapped(
'product_attribute_value_id'
)
def _search_product_attribute_value_ids(self, operator, value):
attr_values = self.env['product.attribute.value'].search([
('name', 'ilike', value)
])
if not attr_values:
return [('id', '=', False)]
products = self.env['product.product'].search([
('product_template_attribute_value_ids.product_attribute_value_id',
'in', attr_values.ids)
])
if not products:
return [('id', '=', False)]
return [('product_id', 'in', products.ids)]
Understanding the Compute + Search Method
The product_attribute_value_ids field is defined with three key attributes. The compute parameter specifies the method that populates the field value for each quant record. It traverses the quant's product_id, accesses the product template attribute values, and extracts the actual attribute value records through the mapped method.
The search parameter defines a custom search method that Odoo calls whenever this field appears in a domain filter. When a user types a value in the search bar, Odoo invokes this method with operator='ilike' and value=<what they typed>. The method must return a standard Odoo domain, which is a list of tuples that will be applied to stock.quant.
def _search_product_attribute_value_ids(self, operator, value):
# Find matching attribute values by name
attr_values = self.env['product.attribute.value'].search([
('name', 'ilike', value)
])
if not attr_values:
return [('id', '=', False)]
# Find product variants that carry any of those attribute values
products = self.env['product.product'].search([
('product_template_attribute_value_ids.product_attribute_value_id',
'in', attr_values.ids)
])
if not products:
return [('id', '=', False)]
return [('product_id', 'in', products.ids)]
Important Design Note
The field is defined with store=False, meaning it is not persisted in the database. The compute method runs on-demand, and the _search method intercepts search queries to resolve them through product relationships. This keeps the database schema clean while providing full search capability.
Step 3: Create the Search View Inheritance
The final piece is inheriting the stock.quant search view to add the new field with a filter_domain. This tells Odoo to use the field in the search bar but apply a custom domain filter when doing so.
stock.quant.search.inherit
stock.quant
Understanding filter_domain
The filter_domain attribute defines an alternative search domain that is used instead of the field's search method. The special keyword self represents the user's search input. This domain navigates from stock.quant through product_id, then through product_template_attribute_value_ids, and finally compares the attribute value's name using ilike against the typed value.
Step 4: Install and Test the Module
Place the product_attr_search folder in your Odoo addons directory, update the apps list, and install the module from the Apps menu. Once installed, navigate to Inventory → Reporting → Stock at Date or any stock inventory view.
Type an attribute value such as "Red", "Large", or "128GB" into the search bar. The inventory list should instantly filter to show only quants whose product variants carry those attribute values. This works across all product lines, making it possible to find every variant with a specific attribute regardless of the product it belongs to.
Place the Module in Addons
Copy the product_attr_search folder to your Odoo addons path, typically /opt/odoo/addons/ or the custom addons directory configured in odoo.conf.
Update Apps List
Activate developer mode by going to Settings → Activate Developer Mode, then go to Apps → Update Apps List to make the new module visible.
Install the Module
Search for "Product Attribute Search" in the Apps list and click Install. The module installs instantly with no additional configuration required.
Test Attribute Search
Navigate to Inventory → Reporting → Stock at Date. Type an attribute value like "Red" in the search bar and confirm that the grid filters to show only matching quants.
Extending the Pattern to Other Views
The same technique can be applied to other Odoo views. For stock.move.line (detailed operations in a delivery or receipt), the model chain is product_id.product_template_attribute_value_ids.product_attribute_value_id.name — exactly the same dotted path, just applied to a different parent model. Inherit the relevant search view and add the field with the appropriate filter_domain.
| Model | View to Inherit | Dotted Path |
|---|---|---|
| stock.quant | stock.quant_search_view | product_id → product_template_attribute_value_ids → product_attribute_value_id.name |
| stock.move.line | stock_move_line_view_search | product_id → product_template_attribute_value_ids → product_attribute_value_id.name |
| sale.order.line | sale.order.line.search | product_id → product_template_attribute_value_ids → product_attribute_value_id.name |
| purchase.order.line | purchase_order_line_search | product_id → product_template_attribute_value_ids → product_attribute_value_id.name |
No Security Rules Required
The module does not define any new models or new records — it only extends an existing model and an existing view. Users who already have access to the stock inventory view automatically have access to the new search field. No ir.rule or ir.model.access records are needed.
Before and After: Warehouse Search Experience
Before: No Attribute Search
Typing "Red" in the default stock inventory search returns nothing unless a product name contains the word "Red". Warehouse staff must manually browse product hierarchies or use complex filter combinations to locate variants by attribute.
After: Attribute-Aware Filtering
Typing "Red" instantly filters the inventory to show only quants with red variants. The system resolves the attribute name across all product lines, displaying all matching inventory in one view with no manual navigation.
This module demonstrates a clean, minimal approach to extending Odoo's search capabilities. By leveraging computed fields with custom search methods and a well-placed filter_domain, you add significant functionality with fewer than 50 lines of Python code. The pattern applies across multiple Odoo models, making it a valuable addition to any developer's toolkit for customizing Odoo inventory workflows.
Frequently Asked Questions
Do I need to add security rules or access rights for this module?
No. The module does not define any new models or new records — it only extends an existing model and an existing view. Users who already have access to the stock inventory view will automatically have access to the new search field. No ir.rule or ir.model.access records are needed.
Can I add this attribute search to delivery orders or sales order lines?
Yes. The model chain is slightly different for each view, but the pattern is identical. For stock.move.line, the path is product_id.product_template_attribute_value_ids.product_attribute_value_id.name. Inherit the relevant search view and add the field with the appropriate filter_domain.
Does the computed field affect database performance?
The field is defined with store=False, meaning no additional database columns are created. The compute method runs on-demand only when the field is accessed, and the _search method resolves queries through existing product relationships. Performance impact is minimal.
What happens if the user searches for an attribute value that does not exist?
The _search method returns [('id', '=', False)] when no matching attribute values are found, resulting in an empty result set. The user sees no quants displayed, which clearly indicates that no inventory matches the typed attribute value.
Can the search handle partial or case-insensitive attribute values?
Yes. The _search method uses the ilike operator, which performs case-insensitive partial matching. Typing "red", "RED", or "Re" will all match "Red" attribute values. The filter_domain in the search view also uses ilike for consistent behavior.
Need Help with Odoo Custom Module Development?
Our Odoo development experts can help you build custom modules, extend inventory search capabilities, integrate attribute-based filtering across your Odoo instance, and optimize warehouse workflows for maximum efficiency.
About the author
Founder & Odoo Practice Lead, Braincuber Technologies
Founder of Braincuber. Has scoped and shipped 500+ Odoo implementations for US mid-market and global brands. Takes every founder call personally — no SDR layer between buyers and the people building the system.
