Enable Dark Mode!
how-to-use-hooks-for-data-patching-in-odoo-19.jpg
By: Swaraj Pallatt

How to Use Hooks for Data Patching in Odoo 19

Technical

In Odoo development, data often needs to be updated when modules are installed or modified. Keeping existing records consistent is especially important in production databases that contain large amounts of data. Manual updates can become difficult and time-consuming, which is why automated data patching is commonly used.

This is where hooks for data patching become useful. Hooks allow developers to execute custom logic automatically during a module’s lifecycle, making it easier to update existing records efficiently and reliably.

What is Data Patching?

Data patching refers to the process of updating or modifying existing records in the database programmatically. Instead of manually editing records through the user interface or writing SQL queries, developers can use Python code to apply updates in a controlled and automated way.

Data patching is especially useful when:

  • New fields are added and need default values
  • Existing data contains incorrect or outdated values
  • System configurations need to be updated
  • Data needs to be aligned with the new business logic

Why Use Hooks for Data Patching?

Hooks are designed to execute automatically at specific stages of a module’s lifecycle, such as during installation or upgrade. This makes them highly suitable for applying data patches at the exact moment when changes are required.

Instead of relying on manual updates or external scripts, hooks allow developers to embed data correction logic directly into the module. This ensures that whenever the module is installed or updated, the required data changes are applied consistently across the system.

Using hooks for data patching offers several key advantages:

  • Automation: Data updates are executed automatically without requiring manual intervention, reducing operational effort.
  • Consistency: Ensures that all relevant records are updated uniformly, avoiding partial or inconsistent data states.
  • Efficiency: Capable of handling large volumes of data through optimized ORM operations.
  • Reliability: Minimizes the risk of human error and ensures repeatable, predictable outcomes.

Hooks Used for Data Patching

Odoo provides different types of hooks that execute at specific stages of a module lifecycle.

  • pre_init_hook > Runs before the module is installed.
  • post_init_hook > Runs after the module is installed.
  • uninstall_hook > Runs on module removal.

In Odoo 19, all hooks receive env directly as a parameter.

Setting Up the Model — Inheriting res.partner and Adding the Priority Field

Before writing any hooks, the first step is to define the field that the hooks will work with. In this example, we are adding a priority field to the existing res.partner model in Odoo.

Odoo's res.partner is the built-in model for all contacts — customers, vendors, and companies. We do not modify the original model directly. Instead, we extend it using _inherit, which lets us add new fields and logic without touching Odoo's core code. This is the standard Odoo way of customizing existing models.

The priority field is what the hooks will operate on. The pre_init_hook creates its database column before installation, and the post_init_hook assigns default values to all existing partners after installation. But for those hooks to work using Odoo's ORM — to call search(), write(), and handle field validation — the field must first be properly declared in the model.

Step 1: model/__init__.py

from . import res_partner

Step 2: model/res_partner.py

from odoo import fields, models

class ResPartner(models.Model):
   _inherit = 'res.partner'
   priority = fields.Selection(
       selection=[
           ('low',    'Low'),
           ('normal', 'Normal'),
           ('high',   'High'),
       ],
       string='Priority',
       default='normal',
       index=True,
       help='Set the priority level for this partner to help your team focus on what matters most.'

Step 3: views/res_partner_views.xml

<?xml version="1.0" encoding="utf-8"?>
<odoo>
   <record id="view_partner_tree_priority" model="ir.ui.view">
       <field name="name">res.partner.tree.priority</field>
       <field name="model">res.partner</field>
       <field name="inherit_id" ref="base.view_partner_tree"/>
       <field name="priority">99</field>
       <field name="arch" type="xml">
           <xpath expr="//field[@name='complete_name']" position="after">
               <field name="priority" optional="show"/>
           </xpath>
       </field>
   </record>
       <record id="view_partner_form_priority" model="ir.ui.view">
       <field name="name">res.partner.form.priority</field>
       <field name="model">res.partner</field>
       <field name="inherit_id" ref="base.view_partner_form"/>
       <field name="priority">99</field>
       <field name="arch" type="xml">
           <xpath expr="//h1[contains(@class,'mb-0')]" position="after">
               <div class="d-flex align-items-center gap-2 mt-1">
                   <field name="priority" widget="priority"/>
               </div>
           </xpath>
       </field>
   </record>
</odoo>

Example Using pre_init_hook

This hook runs before the module is installed. It checks if the priority column already exists in the res_partner table. If it does not exist, it creates the column directly using SQL to prepare the database safely before the ORM loads.

Step 1: __init__.py (Module Root)

Define the pre_init_hook function:

from . import models
from odoo.tools.sql import column_exists, create_column
def pre_init_hook(env):
   if not column_exists(env.cr, "res_partner", "priority"):
       create_column(env.cr, "res_partner", "priority", "varchar")

Step 2: __manifest__.py

Register the hook in your manifest file:

{
   'name': 'Partner Priority Update',
   'version': '19.0.1.0.0',
   'category': 'Technical',
   'summary': 'Manage and classify partners by priority level',
   'author': 'Your Company',
   'website': 'https://www.yourcompany.com',
   'license': 'LGPL-3',
   'depends': ['base'],
   'data': [
       'views/res_partner_views.xml',
   ],
   'pre_init_hook': 'pre_init_hook',
   'installable': True,
   'auto_install': False,
   'application': False,
}

What happens when the module installs: Odoo checks the res_partner table in the database. If the priority column does not exist, it is created immediately using SQL before the ORM tries to load the model. This prevents any migration errors on existing databases.

Note: In Odoo 19, pre_init_hook receives env directly. ORM is fully available — use env['model'] or env.cr for SQL operations.

Example Using post_init_hook

This hook runs after the module is fully installed. It finds all existing partner records that have no priority set and automatically assigns them a default value of normal. This ensures all existing data is consistent from day one.

Step 1: __init__.py (Module Root)

Note: Add the following function to the same root __init__.py file alongside pre_init_hook.

def post_init_hook(env):
   partners = env['res.partner'].search([('priority', '=', False)])
   batch_size = 100
   for i in range(0, len(partners), batch_size):
       batch = partners[i:i + batch_size]
       batch.write({'priority': 'normal'})
   env['ir.config_parameter'].sudo().set_param(
       'partner_priority_update.default_priority',
       'normal'

Step 2: __manifest__.py

Register the hook in your manifest file:

{
   'name': 'Partner Priority Update',
   'version': '19.0.1.0.0',
   'category': 'Technical',
   'summary': 'Manage and classify partners by priority level',
   'author': 'Your Company',
   'website': 'https://www.yourcompany.com',
   'license': 'LGPL-3',
   'depends': ['base'],
   'data': [
       'views/res_partner_views.xml',
   ],
   'pre_init_hook': 'pre_init_hook',
   'post_init_hook': 'post_init_hook',
   'installable': True,
   'auto_install': False,
   'application': False,
}

What happens when the module installs: Odoo searches for all partner records where priority is empty. It updates them in batches of 100 at a time, writing normal as the priority value. Once complete, every existing partner in the system has a priority value without any manual work.

It also saves a system parameter with the key 'partner_priority_update.default_priority' so the uninstall_hook can find and remove it later.

Output you will see in Contacts:

  • Open Contacts list view
  • Every existing partner shows Normal in the Priority column
  • Any new partner created after installation also defaults to Normal

Note: Always use batch processing for large datasets to avoid memory issues and server timeouts.

Example Using uninstall_hook

This hook runs when the module is uninstalled. It removes the configuration data that was created during installation so no leftover data remains in the database after the module is removed.

The post_init_hook stored a config parameter during installation. This hook removes it.

Step 1: __init__.py (Module Root)

Note: Add the following function to the same root __init__.py file alongside the other hooks.

def uninstall_hook(env):
   param = env['ir.config_parameter'].sudo().search([
       ('key', '=', 'partner_priority_update.default_priority')
   ])
   if param:
       param.unlink()

Step 2: __manifest__.py

Register the hook in your manifest file:

{
   'name': 'Partner Priority Update',
   'version': '19.0.1.0.0',
   'category': 'Technical',
   'summary': 'Manage and classify partners by priority level',
   'author': 'Your Company',
   'website': 'https://www.yourcompany.com',
   'license': 'LGPL-3',
   'depends': ['base'],
   'data': [
       'views/res_partner_views.xml',
   ],
   'pre_init_hook': 'pre_init_hook',
   'post_init_hook': 'post_init_hook',
   'uninstall_hook': 'uninstall_hook',
   'installable': True,
   'auto_install': False,
   'application': False,
}

What happens when the module uninstalls: Odoo searches for the config parameter with the key partner_priority_update.default_priority that was stored during installation. If it finds it, it deletes it. This keeps the database clean with no leftover data after the module is removed.

Output you can verify:

  • Before uninstall > go to Settings > Technical > Parameters > System Parameters > search partner_priority_update > you will see it
  • After uninstall > search again > it is gone

Note: Always clean up data your module created. This prevents database clutter after uninstallation.

When Not to Use Hooks

  • Avoid using hooks for extremely large datasets without proper batching, as it may impact performance during installation
  • Do not use hooks for logic that needs to run on every module upgrade; use migration scripts instead
  • Avoid placing heavy or time-consuming operations inside hooks, as they can slow down module installation

Using hooks for data patching in Odoo 19 provides a powerful and automated way to maintain data consistency across modules. By leveraging hooks like post_init_hook, developers can ensure that existing records, configurations, and system data are properly updated during installation without any manual effort.

This approach not only improves efficiency but also guarantees that every deployment remains consistent and reliable. Whether it’s updating existing records, setting default values, or configuring system parameters, hooks make the process seamless and production-ready.

When used correctly with proper checks and optimized logic, hooks help build robust Odoo modules that are easier to maintain, scale, and deploy.

To read more about Overview of Import Hooks in Odoo 19, refer to our blog Overview of Import Hooks in Odoo 19.


Frequently Asked Questions

When should I use pre_init_hook instead of post_init_hook?

Use pre_init_hook when you need to prepare the database schema before the module is installed, such as creating columns using SQL before the ORM loads the model. Use post_init_hook when you want to update records, create data, or configure the system after installation using the ORM.

Does post_init_hook run on module upgrade?

No, the post_init_hook is executed only once during the initial installation of the module. It will not run again when the module is upgraded.

Can I update existing records using hooks?

Yes, hooks are commonly used to update or fix existing records.

Is it safe to use ORM in hooks?

ORM is fully safe to use in all three hooks — pre_init_hook, post_init_hook, and uninstall_hook — because all of them receive env directly as a parameter.

What happens if a hook fails during module installation?

If a hook raises an exception, the entire module installation process will fail and the transaction will be rolled back. This ensures that no partial or inconsistent data is saved in the database. It is recommended to handle critical logic carefully and test hooks before deploying to production.

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



0
Comments



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message