The search_read() method is an essential ORM method in Odoo that combines the functionality of both search() and read() operations into a single, highly efficient call. This powerful method streamlines data retrieval by searching for records based on domain criteria and immediately returning their field values in dictionary format. For developers building efficient Odoo applications, mastering search_read() is crucial for optimizing performance and reducing database queries.
What is the Search_read() Method?
The search_read() method is a convenience method that performs a search operation followed by a read operation in a single database query. Instead of calling search() to find records and then read() to retrieve their values, search_read() accomplishes both tasks at once, returning a list of dictionaries containing the specified field values for matching records.
Syntax:
Model.search_read(domain=None, fields=None, offset=0, limit=None, order=None, load='_classic_read')
Parameters:
- domain: Search criteria to filter records. If not provided or empty, retrieves all records.
- fields: A list of field names to return. If not specified, all fields are retrieved.
- offset: Number of records to skip (useful for pagination).
- limit: Maximum number of records to return.
- order: Sorting specification for the results.
- load: Controls relational field loading behavior (default is '_classic_read').
Returns: A list of dictionaries mapping field names to their values, with one dictionary per matching record.
Why Use Search_read()?
The search_read() method offers significant advantages over using search() and read() separately. By combining both operations, it reduces the number of database queries, decreases network overhead, and improves overall application performance. This is particularly valuable when retrieving data for reports, exports, or API responses where you need specific fields from filtered records.
Searching with Domain Criteria
The domain parameter in search_read() works exactly like the domain in search(), allowing you to filter records using complex criteria. Domains use a specific syntax with tuples containing field names, operators, and values.
Example: Domain Filtering
# Find active customers in the United States
us_customers = self.env['res.partner'].search_read(
domain=[
('customer_rank', '>', 0),
('country_id.code', '=', 'US'),
('active', '=', True)
],
fields=['name', 'city', 'state_id', 'email']
)
Specifying Fields to Retrieve
One of the key benefits of search_read() is the ability to specify exactly which fields you need, reducing data transfer and improving performance.
Example: Selecting Specific Fields
# Retrieve only essential invoice information
invoices = self.env['account.move'].search_read(
domain=[
('move_type', '=', 'out_invoice'),
('state', '=', 'posted')
],
fields=['name', 'partner_id', 'invoice_date', 'amount_total']
)
When no fields are specified, search_read() retrieves all fields:
# Retrieves all fields (less efficient)
all_data = self.env['res.partner'].search_read(
domain=[('id', '=', 1)]
)
Pagination with Offset and Limit
The offset and limit parameters enable efficient pagination of large datasets, allowing you to retrieve data in manageable chunks.
Example: Implementing Pagination
def get_paginated_products(self, page=1, items_per_page=20):
"""Retrieve products with pagination"""
offset = (page - 1) * items_per_page
products = self.env['product.product'].search_read(
domain=[('sale_ok', '=', True)],
fields=['name', 'list_price', 'qty_available'],
offset=offset,
limit=items_per_page,
order='name'
)
return products
# Get first page
page1 = get_paginated_products(page=1, items_per_page=20)
# Get second page
page2 = get_paginated_products(page=2, items_per_page=20)
Sorting Results with Order Parameter
The order parameter allows you to sort search results by one or more fields in ascending or descending order.
Example: Ordering Results
# Order by single field ascending
recent_orders = self.env['sale.order'].search_read(
domain=[('state', '=', 'sale')],
fields=['name', 'date_order', 'amount_total'],
order='date_order desc',
limit=10
)
# Order by multiple fields
sorted_products = self.env['product.product'].search_read(
domain=[('active', '=', True)],
fields=['name', 'categ_id', 'list_price'],
order='categ_id, list_price desc'
)
Working with Relational Fields
Search_read() handles relational fields similarly to the read() method, with Many2one fields returned as tuples and One2many/Many2many fields returned as lists of IDs.
Many2one Fields
orders = self.env['sale.order'].search_read(
domain=[('state', '=', 'sale')],
fields=['name', 'partner_id', 'user_id']
)
# Result with Many2one fields:
# [{'id': 1,
# 'name': 'SO001',
# 'partner_id': (5, 'John Doe'),
# 'user_id': (2, 'Admin User')}]
One2many and Many2many Fields
partners = self.env['res.partner'].search_read(
domain=[('customer_rank', '>', 0)],
fields=['name', 'child_ids', 'category_id']
)
# Result:
# [{'id': 1,
# 'name': 'ABC Company',
# 'child_ids': [10, 11, 12], # List of child contact IDs
# 'category_id': [2, 5]}] # List of category IDs
Using load Parameter
The load parameter controls how relational fields are formatted in the response, similar to the read() method.
Default Load Behavior
# With default load='_classic_read'
data = self.env['sale.order'].search_read(
domain=[],
fields=['name', 'partner_id'],
limit=5
)
# partner_id returns as: (5, 'Partner Name')
Using load=None
# With load=None (only IDs for Many2one)
data = self.env['sale.order'].search_read(
domain=[],
fields=['name', 'partner_id'],
load=None,
limit=5
)
# partner_id returns as: 5
The search_read() ORM method is a powerful and efficient tool for retrieving filtered data from Odoo databases. By combining search and read operations into a single call, it reduces database queries and improves application performance. Whether you're building reports, APIs, exports, or dashboards, understanding how to effectively use search_read() with its parameters—domain, fields, offset, limit, and order—is essential for professional Odoo development. The method's ability to handle complex filtering, pagination, and field selection makes it indispensable for building scalable, high-performance Odoo applications.
To read more about How to Create() orm method in Odoo 19, refer to our blog How to Create() orm method in Odoo 19.