Inspired by: Boost Your Odoo Performance with @lazy_property
Every millisecond counts when you’re managing a robust ERP system like Odoo. On large-scale models such as res.partner or sale.order, sluggish operations can significantly impact user experience and overall system efficiency. This is where Odoo lazy_property performance optimization becomes not just a luxury, but a necessity. By intelligently caching computationally expensive values, Odoo’s @lazy_property decorator can dramatically accelerate your application.
This comprehensive guide will walk you through, step-by-step, how to leverage @lazy_property to achieve superior Odoo lazy_property performance. We’ll cover what it is, why it’s essential, when to use it, and provide a practical, detailed tutorial that empowers you to implement this powerful optimization technique in your own Odoo projects. Get ready to transform your Odoo environment into a faster, more responsive platform.
What Exactly is @lazy_property?
At its core, @lazy_property is a special decorator found within Odoo’s odoo.tools module. It transforms a method into a property that, when accessed for the first time within a single Odoo request, computes its value and then caches that result. For all subsequent accesses of the same property on the same record within that identical request, Odoo will bypass the computation and return the cached value.
Think of it as a smart, temporary cache specifically designed for model properties. Unlike a regular @property in Python, which re-executes its method every time it’s called, @lazy_property ensures that heavy lifting only happens once per record per request. This mechanism is fundamental to achieving effective Odoo lazy_property performance.
Why is Odoo lazy_property Performance Crucial for Your ERP?
The impact of optimizing with @lazy_property extends far beyond just saving a few milliseconds. It directly contributes to a more efficient, scalable, and user-friendly Odoo experience. Here’s why adopting this decorator is a game-changer:
- Prevents Redundant Database Queries: Without
@lazy_property, accessing a computed property that involves a database query multiple times within the same request will lead to repetitive queries. This creates unnecessary load on your database server and network.Odoo lazy_property performanceensures these queries are executed only once. - Optimizes Expensive Calculations: Many Odoo models require properties derived from complex calculations or aggregations across numerous related records. These operations can be resource-intensive. Caching their results with
@lazy_propertymeans these expensive computations are performed only once per record per request, dramatically speeding up subsequent accesses. - Cleaner and More Maintainable Code: Manual caching logic can be verbose and prone to errors.
@lazy_propertyencapsulates this caching mechanism beautifully, allowing developers to write cleaner, more readable code that focuses on the business logic rather than cache management. - Direct Improvement in Runtime Efficiency: The most tangible benefit is the immediate improvement in runtime efficiency. Faster loading views, quicker report generation, and more responsive API endpoints are direct results of harnessing
Odoo lazy_property performance. This leads to a smoother, more satisfying user experience for everyone interacting with your Odoo system. - Scalability for High-Load Scenarios: In environments with many concurrent users or complex workflows, reducing redundant operations is key to scalability.
@lazy_propertyhelps alleviate database pressure, allowing your Odoo instance to handle heavier loads more gracefully.
When to Leverage @lazy_property for Optimal Performance
While powerful, @lazy_property is not a silver bullet for all performance issues. Knowing when and where to apply it is crucial for maximizing Odoo lazy_property performance benefits without introducing unexpected behavior.
Use @lazy_property in the following scenarios:
- Value Immutability During Request Lifecycle: The most critical condition is that the computed value must not change during the lifetime of a single user request. If the underlying data (and thus the computed value) could be modified within the same request after the property is first accessed, then
@lazy_propertywill return an outdated, incorrect cached value. - Heavy Database Operations: If a property’s computation involves extensive database queries, such as
search_count,read_group, or complex joins across multiple models, it’s an excellent candidate. - Complex or Time-Consuming Python Calculations: For properties that require significant Python processing, mathematical operations, or iterative logic over large datasets,
@lazy_propertycan prevent repeated execution of this costly code. - Common Use Cases:
- Counting Related Records:** For example, the number of sale orders for a partner, the number of tasks for a project, or the count of invoices for a customer.
- **Aggregated Values:** Summing up amounts from related records, calculating average prices, or determining total quantities.
- **Pre-processed Settings or Configurations:** Fetching complex system settings or user-specific preferences that require multiple database lookups but don’t change during a single interaction.
Pro Tip: Always profile your code before and after implementing @lazy_property to confirm the performance gains. Odoo’s debug mode (accessible by appending ?debug=1 to your URL) and server logs can provide valuable insights into query timings and method execution.
Step-by-Step Tutorial: Implementing Odoo lazy_property Performance
Let’s dive into a practical example. We’ll implement @lazy_property to efficiently count the number of sale orders associated with each business partner (res.partner), a common scenario where Odoo lazy_property performance can make a significant difference.
This tutorial assumes you have a basic understanding of Odoo development and module creation. For more details on module development, you can refer to the Odoo developer documentation.
1. Understanding the Core Concept
Before writing any code, internalize what we’re trying to achieve: we want to calculate sale_order_count for a partner. This calculation involves a database query. Without @lazy_property, if you access partner.sale_order_count multiple times within the same Odoo web request (e.g., in different parts of a view or multiple methods), that database query will run repeatedly. @lazy_property will ensure it runs only once per partner per request.
2. Setting Up Your Development Environment
Ensure you have a custom Odoo module set up. If not, create a new module (e.g., my_custom_module). Add it to your Odoo addons path and ensure it’s loaded by your Odoo instance. For a comprehensive guide on setting up your environment, consider exploring resources on Odoo development best practices.
3. Importing lazy_property
Inside your Python file where you’ll be extending the res.partner model (e.g., my_custom_module/models/res_partner.py), you need to import the lazy_property decorator.
from odoo import models, fields, api
from odoo.tools import lazy_property # This line is crucial!
Explanation:
The from odoo.tools import lazy_property line explicitly imports the decorator from Odoo’s utility library, making it available for use in your model.
4. Inheriting the Model and Defining Your Property
Now, let’s extend the res.partner model and define our sale_order_count property using @lazy_property.
from odoo import models, fields, api
from odoo.tools import lazy_property
class ResPartner(models.Model):
_inherit = 'res.partner'
@lazy_property
def sale_order_count(self):
"""Cache the count of Sale Orders per partner for this request."""
print(f"--- Calculating sale_order_count for partner {self.display_name} (ID: {self.id}) ---") # For demonstration
return self.env['sale.order'].search_count([('partner_id', '=', self.id)])
Detailed Code Explanation:
class ResPartner(models.Model):**: We define a Python classResPartnerthat inherits frommodels.Model, a standard practice for Odoo models.- **
_inherit = 'res.partner'**: This Odoo-specific attribute tells Odoo that this class is extending the existingres.partnermodel, rather than creating a new one.res.partneris Odoo’s built-in model for contacts, customers, and vendors. - **
@lazy_property**: This is the magic decorator. Whensale_order_countis accessed, this decorator intercepts the call. If the value hasn’t been computed and cached for the currentself(i.e., the specific partner record) within the current Odoo request, it allows the method below it to run. Once the method returns a value,@lazy_propertycaches this result. For subsequent accesses within the same request, it returns the cached value directly without executing the method again. Theprintstatement is added here temporarily to visibly demonstrate when the calculation actually runs. **def sale_order_count(self):**: This defines the method that will compute our property. It takesselfas an argument, representing the currentres.partnerrecord(s).- **
"""Cache the count of Sale Orders per partner for this request."""**: A docstring describing the purpose of the property, which is good practice. - **
return self.env['sale.order'].search_count([('partner_id', '=', self.id)])**: This line contains the actual logic for counting sale orders.- **
self.env**: This object provides access to the current Odoo environment, including all available models. It’s a key part of Odoo’s ORM (Object-Relational Mapping). - **
self.env['sale.order']**: This accesses thesale.ordermodel, which represents sales orders in Odoo. - **
.search_count(...)**: This is an Odoo ORM method that efficiently counts records matching specific criteria without fetching the full record data. It’s much faster thansearch()followed bylen(). - **
[('partner_id', '=', self.id)]**: This is an Odoo domain, which specifies the search criteria. It instructs Odoo to countsale.orderrecords where thepartner_idfield (which links a sale order to a partner) is equal to the ID of the current partner record (self.id).
- **
5. Integrating with Odoo Views (Optional, but Recommended for Visibility)
To see your sale_order_count in action within the Odoo interface, you’ll need to add it to a view. You can extend the res.partner form view in an XML file (e.g., my_custom_module/views/res_partner_views.xml).
<odoo>
<data>
<record model="ir.ui.view" id="res_partner_view_form_inherit_my_custom_module">
<field name="name">res.partner.form.inherit.my_custom_module</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='sales_purchases']/group" position="inside">
<field name="sale_order_count" string="Total Sale Orders" readonly="1"/>
</xpath>
</field>
</record>
</data>
</odoo>
Explanation:
- This XML code inherits from the standard
base.view_partner_formview. - The
<xpath>expression targets theSales & Purchasestab within the partner form. - It then adds a new
<field>tag to display oursale_order_countproperty.readonly="1"is essential because this is a computed, not an editable, field.
6. Updating Your Module Manifest
Ensure your my_custom_module/__manifest__.py file correctly declares dependencies and references your new XML view.
{
'name': 'My Custom Performance Module',
'version': '1.0',
'summary': 'Enhances Odoo performance with lazy_property for partner sale order counts.',
'depends': ['base', 'sale'], # 'sale' module is required because we're referencing 'sale.order'
'data': [
'views/res_partner_views.xml', # Reference your XML view file
],
'installable': True,
'application': False,
'auto_install': False,
'license': 'LGPL-3',
}
Explanation:
'depends': ['base', 'sale']**: Thebasemodule is always a dependency for custom modules. We also addsalebecause our code interacts with thesale.ordermodel. If you don’t have the Sales module installed, Odoo won’t find thesale.ordermodel.- **
'data': ['views/res_partner_views.xml']**: This ensures your XML view is loaded when the module is installed or updated.
7. Deploying and Testing Your Changes
Finally, update your custom module in Odoo.
- Restart your Odoo server (if you made changes to Python files).
- Navigate to Apps in Odoo.
- Search for
My Custom Performance Module(or whatever you named it). - Click Upgrade.
Now, go to a res.partner record (e.g., a customer). When you open the form, observe the sale_order_count. If you monitor your Odoo server logs (where we added the print statement), you should see the “— Calculating…” message only once per partner when the form is initially loaded or refreshed, even if the sale_order_count is displayed in multiple places or accessed by other methods in the same request. This visual cue confirms the Odoo lazy_property performance optimization is active.
How lazy_property Delivers Superior Odoo lazy_property performance
The core mechanism behind @lazy_property‘s effectiveness is its intelligent caching strategy:
- First Access:** When a user or another part of the Odoo system accesses
partner.sale_order_countfor a specificres.partnerrecord (self) for the very first time within a particular Odoo web request, thesale_order_countmethod (which contains thesearch_countquery) is fully executed. The database is queried, and the count is computed. - **Caching:** The result of this computation (the actual count) is then stored in an internal cache associated with that specific
partnerrecord and the ongoing HTTP request. - **Subsequent Accesses:** If
partner.sale_order_countis accessed again for the same partner record within the same HTTP request,@lazy_propertyintercepts the call, finds the cached value, and immediately returns it. Thesale_order_countmethod is not executed again, and no new database query is performed. - **Request Lifecycle:** Once the Odoo web request completes (e.g., the page loads, an API call returns), the temporary cache is cleared. The next time the property is accessed in a new request, the process restarts, ensuring data freshness for each distinct interaction.
This approach ensures that expensive operations are only performed when absolutely necessary, drastically reducing redundant work and significantly boosting Odoo lazy_property performance.
Real-World Impact and Case Studies
Imagine an Odoo instance with thousands of partners and tens of thousands of sale orders. A typical user might open a partner form, then navigate to a related report, then perhaps a dashboard displaying partner statistics. Each of these actions could potentially trigger calculations like sale_order_count.
- Scenario Without
@lazy_property:** Each interaction would trigger new database queries for every count, leading to slow page loads, database overload, and a frustrating user experience, especially during peak hours. If a single page displayssale_order_countfor 50 partners, that’s 50 separatesearch_countqueries per page load! - **Scenario With
@lazy_property:** All these interactions within the same request lifecycle would only trigger thesearch_countquery once per partner. This reduction in database calls and computation cycles translates directly to:- Faster Views:** Partner forms, list views, and related reports load significantly quicker.
- **Optimized API Responses:** Integrations relying on partner data receive faster responses.
- Smoother User Experience:** Users perceive the system as more responsive and efficient.
This simple optimization can save hundreds of milliseconds, or even seconds, on complex pages or in high-transaction environments, making Odoo lazy_property performance a key component of a responsive ERP system.
Critical Considerations: When Not to Use @lazy_property
Despite its benefits, @lazy_property is not a universal solution. Misusing it can lead to incorrect data and debugging headaches. Always keep these points in mind:
- Volatile Values:** If the value of your property can legitimately change within the same Odoo request after its initial computation,
@lazy_propertyis unsuitable. For example, if you have a property calculating aninvoice_total, and a new invoice is created or an existing one is modified later in the same request, the cachedinvoice_totalwould be outdated. For such dynamic scenarios, you might need@api.dependsfields or manual caching with careful invalidation logic. - Trivial Calculations:** For properties that involve very simple, fast calculations or directly return a stored field, the overhead of
@lazy_property‘s caching mechanism might outweigh any potential performance gains. Only apply it to genuinely expensive operations. - Memory Usage:** While typically minimal for individual properties, excessive use of
@lazy_propertyfor very large datasets on every single record could theoretically consume more memory. Prioritize its use where the computational gain is highest.
Always consider the lifecycle of your data and the scope of your operations. When in doubt, lean towards correctness over premature optimization.
Beyond lazy_property: Holistic Odoo Performance Optimization
While @lazy_property is an excellent tool for specific Odoo lazy_property performance enhancements, comprehensive optimization requires a broader approach. Consider these other areas to fine-tune your Odoo application:
- Database Indexing:** Ensure your frequently queried fields have proper database indexes. This can drastically speed up
searchandsearch_countoperations. - ORM Optimization:** Understand and utilize Odoo’s ORM efficiently. For example, use
sudo()judiciously, employpre_fetchwhere appropriate, and avoid N+1 query problems. - Efficient Field Types:** Choose the most appropriate and efficient field types for your data. Using
Integerfor numbers instead ofChar, for instance, can impact query performance. - Code Profiling:** Regularly profile your custom code to identify bottlenecks. Tools like
py-spyor Odoo’s built-in profiler can be invaluable. - External Caching:** For data that persists beyond a single request, consider implementing more robust external caching mechanisms like Redis or Memcached for certain types of operations.
- Frontend Optimization:** Don’t forget the frontend! Optimize JavaScript, CSS, and reduce image sizes for faster client-side rendering.
For more insights into broader Odoo performance strategies, check out this guide on Odoo Performance Tuning.
Conclusion
Mastering Odoo lazy_property performance with the @lazy_property decorator is a powerful skill for any Odoo developer. By intelligently caching the results of expensive computations, you can significantly reduce database load, accelerate views, and deliver a smoother, more efficient user experience. Remember to apply this tool strategically, focusing on operations where the performance gain is substantial and the data remains stable within a request.
Start integrating @lazy_property into your Odoo development workflow today. You’ll not only see a remarkable improvement in speed but also contribute to a more robust and scalable Odoo ecosystem. The path to a truly responsive ERP begins with smart, targeted optimizations like this.
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.

