The Odoo read_group method is one of the most powerful, yet often underutilized, tools in a developer’s arsenal. If you’ve ever found yourself writing slow, cumbersome loops to calculate totals or group records, you’re about to discover a much better way. This single ORM method can revolutionize how you handle data aggregation, making your custom reports faster, your code cleaner, and your applications more scalable.
This comprehensive guide will walk you through everything you need to know. We’ll start with the basics and progressively move to advanced examples, transforming you into a data aggregation expert. Get ready to unlock the true potential of your Odoo data.
What Exactly is the Odoo read_group Method?
At its core, the Odoo read_group method is a specialized ORM query that performs grouping and aggregation directly at the database level. Think of it as Odoo’s way of executing a GROUP BY
SQL query without you having to write a single line of SQL.
Instead of fetching hundreds or thousands of records with search()
and then looping through them in Python to calculate sums or counts, read_group()
does all the heavy lifting for you in one efficient operation. It returns a concise list of aggregated results, which is significantly faster and uses far fewer server resources.
Why You Absolutely Need to Master This Method
Embracing the Odoo read_group method isn’t just about writing different code; it’s about writing better code. Here’s why it should be a fundamental part of your development workflow:
- Blazing-Fast Performance: By pushing the computation to the database, you eliminate the overhead of Python loops and object instantiation for every record. For large datasets, the performance difference is not just noticeable—it’s game-changing.
- Code Simplicity and Readability: A single, well-structured
read_group()
call replaces dozens of lines of looping and conditional logic. Your code becomes easier to read, understand, and maintain. - Foundation for Powerful Reporting: This method is the engine behind Odoo’s own reporting and list view grouping features. Mastering it allows you to build complex, custom dashboards and reports that are both powerful and performant.
- Enhanced Scalability: As your data grows, applications built with inefficient loops will grind to a halt. An application built using the
Odoo read_group method
will scale gracefully, handling massive amounts of data with ease.
Getting Started: A Practical Walkthrough
Theory is great, but let’s see this powerhouse in action. We’ll build a simple mechanism to group sales orders by customer and see the total count and value.
Step 1: Setting Up Our Playground
To test our code, we’ll create a simple server action. This allows us to trigger our Python code with a button click in the Odoo interface.
First, create a custom module (e.g., my_custom_reporting
). In your module, add an XML file to define the server action.
views/sale_order_views.xml
:
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="action_compute_sales_group" model="ir.actions.server">
<field name="name">Run Sales Read Group</field>
<field name="model_id" ref="sale.model_sale_order"/>
<field name="binding_model_id" ref="sale.model_sale_order"/>
<field name="state">code</field>
<field name="code">
# We will call our Python method on the selected records
model.compute_sales_by_partner()
</field>
</record>
</odoo>
Don’t forget to add this XML file to your __manifest__.py
file.
Step 2: The Core Logic – Calling read_group
Next, let’s create the Python method that our server action will call. In your model file, extend sale.order
.
models/sale_order.py
:
from odoo import models, api
import logging
_logger = logging.getLogger(__name__)
class SaleOrder(models.Model):
_inherit = 'sale.order'
def compute_sales_by_partner(self):
_logger.info("--- Starting read_group demonstration ---")
# 1. Domain: We'll filter for confirmed sales orders only.
domain = [('state', 'in', ['sale', 'done'])]
# 2. Fields: We want the partner and the total amount.
# We also need to specify an aggregation function for numeric fields, like ':sum'.
fields = ['partner_id', 'amount_total:sum']
# 3. Groupby: The field we want to group our results by.
groupby = ['partner_id']
# The magic happens here!
grouped_data = self.env['sale.order'].read_group(domain, fields, groupby)
_logger.info("--- Grouped Data Result ---")
_logger.info(grouped_data)
# Let's make the output prettier
for group in grouped_data:
_logger.info(
f"Customer: {group['partner_id'][1] if group.get('partner_id') else 'N/A'}, "
f"Order Count: {group['__count']}, "
f"Total Sales: {group['amount_total']}"
)
return True # Server actions expect a return value
Step 3: Triggering the Action
Install your module, navigate to the Sales application, select a few sales orders from the list view, and click Action > Run Sales Read Group. Check your Odoo server logs, and you will see the beautifully aggregated data printed out!
Deep Dive: Unpacking the read_group
Parameters
The true power of the Odoo read_group method lies in its parameters. Let’s break them down one by one.
The domain
: Your Data Filter
The domain
is a list of tuples that acts as the WHERE
clause of your query. It filters the records before grouping.
- All Records: An empty list
[]
includes all records. - Specific Condition:
[('state', '=', 'sale')]
includes only confirmed quotations. - Multiple Conditions:
[('amount_total', '>', 1000), ('state', '=', 'sale')]
includes confirmed orders with a total greater than 1000.
For more on creating domains, check out our guide to Odoo ORM Search Domains (this is an example of an internal link).
The fields
: What Data Do You Want?
The fields
parameter is a list of the field names you want to retrieve. Crucially, this is also where you define your aggregation.
- Simple Field:
'partner_id'
- Aggregated Field:
'amount_total:sum'
. The part after the colon (:
) is the aggregator. Common aggregators includesum
,avg
,min
,max
. - Special Fields: The
__count
field is automatically returned, giving you the number of records in each group. The__domain
field is also returned, providing a domain to retrieve the exact records within that group.
The groupby
: The Heart of the Odoo read_group method
This is the most important parameter. It’s a list of fields that tells Odoo how to group the results. This corresponds to the GROUP BY
clause in SQL.
- Single Grouping:
groupby=['partner_id']
groups all records by their associated customer. - Multi-Level Grouping:
groupby=['partner_id', 'state']
first groups by customer, and then creates subgroups based on the order’s state. - Grouping by Date: You can even group by date parts like
groupby=['date_order:month']
to get monthly aggregates.
limit
and offset
: Paginating Your Groups
Just like with a search()
call, limit
and offset
allow you to paginate your results. This is perfect for “Top 10” style reports.
# Get the top 5 customers by sales, after sorting
grouped_data = self.env['sale.order'].read_group(
domain, fields, groupby, orderby='amount_total DESC', limit=5
)
orderby
: Sorting Your Results
The orderby
parameter sorts the final groups, not the individual records. You can sort by any of the fields you’ve requested, including the aggregated ones.
- Sort by Name:
orderby='partner_id'
- Sort by a Number (Descending):
orderby='amount_total DESC'
- Sort by Record Count:
orderby='__count DESC'
For a complete technical reference, the Official Odoo Documentation for read_group is an excellent external resource.
Putting It All Together: Advanced Scenarios
Let’s explore some more complex and practical examples.
Scenario 1: Quarterly Sales Report by Salesperson
Goal: Get the total sales amount for each salesperson, grouped by quarter.
domain = [('state', 'in', ['sale', 'done'])]
fields = ['user_id', 'amount_total:sum']
# Group by salesperson, then by the quarter of the order date
groupby = ['user_id', 'date_order:quarter']
quarterly_report = self.env['sale.order'].read_group(domain, fields, groupby, lazy=False)
# lazy=False ensures the names for user_id and date_order are fetched immediately
_logger.info(quarterly_report)
Scenario 2: Analyzing Product Line Quantities
Goal: Find the total quantity sold for each product across all sales orders. This requires us to query the sale.order.line
model.
domain = [('state', '=', 'sale')] # Filter on the parent order's state
fields = ['product_id', 'product_uom_qty:sum']
groupby = ['product_id']
orderby = 'product_uom_qty DESC' # Show top-selling products first
limit = 10
product_analysis = self.env['sale.order.line'].read_group(
domain, fields, groupby, orderby=orderby, limit=limit
)
_logger.info(product_analysis)
Conclusion: Your New Go-To for Data Aggregation
The Odoo read_group method is more than just a function; it’s a paradigm shift in how you should approach data analysis and reporting in Odoo. By moving computation from Python to the database, you gain incredible performance, write cleaner code, and build applications that can handle enterprise-level data loads without breaking a sweat.
Start by identifying places in your code where you loop through records to calculate a sum or count. Replace them with a read_group
call and witness the difference yourself. It’s a fundamental skill that will set you apart as a proficient and efficient Odoo developer.
What powerful reports or dashboard widgets will you build first? Share your ideas and questions in the comments below
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.