Enable Dark Mode!
a-complete-guide-to-flushrecordset-invalidaterecordset-and-modified-in-odoo-19.jpg
By: Abhijith CK

A Complete Guide to flush_recordset(), invalidate_recordset(), and modified() in Odoo 19

Technical Odoo 19 Odoo Enterprises Odoo Community

When creating custom modules using Odoo 19, most programmers deal with the ORM via functions such as create(), write(), search(), and unlink(). While these functions are enough for regular programming tasks, complex cases may demand that the developer have more knowledge about the synchronization of data in the in-memory cache of Odoo and the PostgreSQL database. It is particularly relevant in cases of using SQL queries directly, improving the performance of queries, or working with computed fields stored in the database. Functions such as flush_recordset(), invalidate_recordset(), and modified() enable this.

The importance of these techniques

Through the use of the API, Odoo caches field values in memory before writing them into the database. The API gives developers a chance to control database writes, cache flushes, and field dependencies calculation. In Odoo 19, the legacy flush() and invalidate_cache() methods on recordsets have been removed. Instead, you must use their modernized and safer equivalents.

1. flush_recordset() and flush_model()

These functions will flush out any uncommitted changes made by the ORM to the database, but without committing the transaction. These must be called before executing any raw SQL query to ensure that SQL reads retrieve the current data.

  • flush_recordset(fnames=None): Flushes pending changes of specific fields only for the current recordset.
  • flush_model(fnames=None): Flushes pending changes of specific fields for all records of the model.
  • self.env.flush_all(): Flushes all pending computations and updates across the current transaction.

Example:

partner.name = "New Name"
 partner.flush_recordset(['name'])
 self.env.cr.execute(
 "SELECT name FROM res_partner WHERE id=%s",
 (partner.id,)
 )
 print(self.env.cr.fetchone())

2. invalidate_recordset() and invalidate_model()

These methods clear out any cache associated with the field values. This way, future reads on those fields will fetch fresh values from the database.

  • invalidate_recordset(fnames=None, flush=True): Clears the cache for specific fields of records in the recordset.
  • invalidate_model(fnames=None, flush=True): Clears the cache for specific fields of all records of the model.

Important Note: By default, flush=True is enabled, meaning pending updates to the fields will be written to the database before invalidating. When running raw SQL updates where you want to discard pending ORM changes, you should call these methods with flush=False.

Example:

self.env.cr.execute(
    "UPDATE res_partner SET name='SQL Updated' WHERE id=%s",
    (partner.id,)
)
partner.invalidate_recordset(['name'], flush=False)
print(partner.name)

3. modified()

The modified() method informs the ORM of changed fields. This ensures that computed fields stored in these fields are correctly recalculated if they are changed outside the normal ORM write process.

Example:

self.env.cr.execute(
 "UPDATE sale_order SET amount_total=1000 WHERE id=%s",
 (order.id,)
 )
 order.invalidate_recordset(['amount_total'], flush=False)
 order.modified(['amount_total'])

Using all three together

When performing raw database updates that affect fields used in computation, follow this pattern to ensure full synchronization:

partner.flush_recordset(['email'])
 self.env.cr.execute(
 "UPDATE res_partner SET email='new@example.com' WHERE id=%s",
 (partner.id,)
 )
 partner.invalidate_recordset(['email'], flush=False)
 partner.modified(['email'])

Key differences

MethodPurposeTypical use
flush_recordset()
flush_model()
Write pending ORM changes to DBBefore raw SQL reads
invalidate_recordset()
invalidate_model()
Clear cached valuesAfter raw SQL updates (usually with flush=False)
modified()Trigger dependency recomputation After non-ORM field updates

Best Practices

  • Consider using ORM techniques where applicable. Avoid direct SQL writes unless absolutely necessary.
  • Before running any raw SQL queries based on pending writes, use flush_recordset() or flush_model().
  • After executing any raw SQL updates, call invalidate_recordset(..., flush=False) or invalidate_model(..., flush=False).
  • If raw SQL changes columns used in computation, consider modified() to propagate updates to dependent computed fields.
  • Note that flushing does not commit the database transaction.

The flush, invalidate, and modified methods are tools you probably won't use in everyday Odoo development, but they become essential once things get more complex, especially when you are mixing raw SQL with the ORM, and you need to keep the cache and database in sync.

Rule of thumb: if you can, stick with the ORM. It does caching and dependency tracking for you so you rarely have to think about these things. But sometimes you will have to deal with raw database operations, and when you do, you will have to use the right combination of these methods to ensure that the ORM does not have stale data.

To read more about Overview of Records and Recordsets in Odoo 19, refer to our blog Overview of Records and Recordsets in Odoo 19.


If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



WhatsApp