Skip to content

Odoo Hooks Explained

  • Odoo
Odoo Hooks

Welcome to this in-depth tutorial where Odoo Hooks Explained will be our central theme. Developers often need to run custom logic at specific points in an Odoo module’s lifecycle, such as before or after installation, during an update, or just before uninstallation. Odoo provides a powerful mechanism called “Hooks” to achieve this. Consequently, understanding and utilizing these hooks effectively can greatly simplify tasks like data migration, initial configuration setup, and necessary cleanup operations. Therefore, this guide will walk you through the different types of Odoo hooks, demonstrate how to implement them, and explore practical examples to help you master this essential Odoo development concept.

Mastering Module Lifecycle Events

source : https://www.linkedin.com/posts/ali-el-mohammady-74670b282_odoo-erp-hooks-activity-7329860831452598272-dfQ_/?rcm=ACoAAAUPxrsB223ygjog-L-91vracbuFPIw07-c

Understanding the Odoo Module Lifecycle and the Role of Hooks

Before we dive into the specifics of Odoo Hooks Explained, it’s important to grasp the Odoo module lifecycle. Essentially, every Odoo module goes through several distinct phases:

  1. Installation: This occurs when you first install a module into an Odoo database.
  2. Upgrade: This happens when you update an already installed module to a newer version.
  3. Uninstallation: This is the process of removing a module from the database.
  4. Server Startup: This refers to the point when the Odoo server starts, loading all installed modules.

During these phases, you might need to perform specific actions. For instance, you might want to create default data when a module is installed, migrate existing data when a module is upgraded, or clean up custom database tables when a module is uninstalled. This is precisely where Odoo hooks become invaluable, providing entry points to inject your custom Python code at these critical junctures. Using these Odoo module lifecycle hooks allows for cleaner, more maintainable module development.

Exploring Different Types of Odoo Hooks

Odoo offers several types of hooks, each designed to execute at a different stage of the module lifecycle. Let’s explore each one with detailed explanations and practical examples of these Odoo custom logic hooks.

Pre-Init Hooks (pre_init_hook): Actions Before Module Installation

The pre_init_hook executes before Odoo even begins the standard installation process for your module. This means it runs before Odoo creates database tables from your models or loads any XML/CSV data files defined in your manifest.

Purpose and Use Cases for Pre-Initialization Hooks

You typically use pre_init_hook for tasks such as:

  • Pre-installation checks: For example, verifying if certain system dependencies are met or if another conflicting module is not installed.
  • Setting up initial configurations: This could involve creating essential records in other modules that your module depends on before its own models are created.
  • Modifying the database schema in advance: In rare cases, you might need to perform raw SQL operations to prepare the database schema.
  • Data preparation: If your module’s installation depends on certain data being present or in a specific state, a pre-init hook can ensure this.
Implementing a pre_init_hook

To implement a pre_init_hook, you define a Python function (conventionally named starting with an underscore, e.g., _my_pre_init_hook) that accepts a single argument: cr (the database cursor). You then register this function in your module’s __manifest__.py file.

Let’s look at an example based on the provided context for a clearer understanding of Odoo Hooks Explained:

# In your module's Python file (e.g., hooks.py or __init__.py)
from odoo import api, SUPERUSER_ID

def _first_pre_init_hook(cr):
    print("Pre init hook before install module: Starting custom pre-installation logic.")
    # Example: Update mobile for partners where mobile is not set
    # This is a direct SQL execution, useful before models are fully loaded
    cr.execute("""UPDATE res_partner SET mobile='0102568798' WHERE mobile IS NULL""")
    # It's crucial to commit changes made with cr.execute if they should persist
    # However, Odoo typically handles commits at the end of successful hook execution.
    # For explicit control or multiple operations, cr.commit() can be used cautiously.
    # In this specific example from the context, cr.commit() was used.
    cr.commit()
    print("Pre init hook: Mobile numbers updated for partners where mobile was null.")

    # You can also get an Odoo environment if needed, though models from the current
    # module are not yet available. You can interact with models from other installed modules.
    env = api.Environment(cr, SUPERUSER_ID, {})
    # Example: Call a method on an existing model (e.g., from a dependency)
    # Assuming 'res.partner' has a custom method 'hook_method' (defined elsewhere or in a base module)
    # For demonstration, let's assume hook_method exists and performs some logging or check.
    if hasattr(env['res.partner'], 'hook_method'):
        print("Pre init hook: Attempting to call hook_method on res.partner.")
        env['res.partner'].hook_method()
        print("Pre init hook: Called hook_method on res.partner.")
    else:
        print("Pre init hook: hook_method not found on res.partner.")
    print("Pre init hook execution finished.")

In this _first_pre_init_hook example, we first print a message to indicate its execution. Then, we use cr.execute to directly update the res_partner table, setting a default mobile number for partners who don’t have one. This demonstrates a common use case for pre-init hooks: preparing data. Subsequently, it attempts to call a method hook_method on res.partner using an Odoo environment. This part highlights that while your module’s models aren’t set up yet, you can still interact with existing parts of Odoo. The cr.commit() ensures the SQL update is saved immediately.

Post-Init Hooks (post_init_hook): Actions After Module Installation

The post_init_hook executes after Odoo has completed the standard installation process for your module. This means your module’s models are created in the database, and its data files (XML, CSV) have been loaded.

Purpose and Use Cases for Post-Initialization Hooks

This is one of the most commonly used Odoo module lifecycle hooks. Typical uses include:

  • Data migration: If your module replaces an old one or changes data structures, you can migrate data from the old structure to the new one.
  • Complex data setup: For creating records that require logic not easily expressed in XML or CSV files, or records that depend on other data created during installation.
  • Additional configurations: Setting up specific configurations based on the initial data or performing actions that require your module’s models to be fully available.
  • Triggering workflows or server actions: After all components are in place.
Implementing a post_init_hook

A post_init_hook function takes two arguments: cr (the database cursor) and registry (the Odoo model registry for the current database).

Here’s an example, continuing with our Odoo Hooks Explained theme, based on the context:

# In your module's Python file
from odoo import api, SUPERUSER_ID

def _second_post_init_hook(cr, registry):
    print("Post init hook after install module: Starting custom post-installation logic.")
    # At this stage, your module's models are available.
    # It's generally preferred to use the Odoo ORM via the env.
    env = api.Environment(cr, SUPERUSER_ID, registry)

    # Example 1: Update VAT for partners where VAT is not set using direct SQL
    # The context shows cr.execute, so we'll reflect that.
    cr.execute("""UPDATE res_partner SET vat='12345' WHERE vat IS NULL""")
    cr.commit() # Commit the direct SQL change
    print("Post init hook: VAT updated for partners where VAT was null using SQL.")

    # Example 2: Update mobile numbers using the ORM
    # The context shows a write operation.
    # Let's assume we want to update all partners' mobile numbers to a new default,
    # or perhaps a specific subset. The context implies a general write.
    # For safety, let's find partners updated by the pre_init_hook or those with the new VAT.
    partners_to_update = env['res.partner'].search([('vat', '=', '12345')])
    if partners_to_update:
        partners_to_update.write({'mobile': '112233'})
        print(f"Post init hook: Updated mobile to '112233' for {len(partners_to_update)} partners using ORM.")
    else:
        print("Post init hook: No partners found with VAT '12345' to update mobile.")

    # Example: Call a method on one of your module's models or a base model
    if hasattr(env['res.partner'], 'another_custom_method_for_post_init'):
        # env['your_module.your_model'].some_setup_method()
        print("Post init hook: Calling another_custom_method_for_post_init if it exists.")
    print("Post init hook execution finished.")

In _second_post_init_hook, we first obtain an Odoo environment. The example then demonstrates updating partner VAT numbers using cr.execute (as shown in the context) and subsequently updates mobile numbers for a subset of partners using the Odoo ORM’s write method. This illustrates the flexibility of post-init hooks, where you can use both direct SQL for certain operations and the ORM for more complex data manipulations now that your models are fully loaded. This is a key aspect of Odoo Hooks Explained.

Uninstall Hooks (uninstall_hook): Actions Before Module Uninstallation

The uninstall_hook executes before Odoo starts the standard uninstallation process for your module. This means your module’s models and data are still present in the database when this hook runs.

Purpose and Use Cases for Uninstallation Hooks

This hook is crucial for cleaning up. Common uses include:

  • Removing custom data: Deleting records created by your module that Odoo wouldn’t automatically remove (e.g., data in tables not directly defined by Odoo models, or specific configuration entries).
  • Reverting configurations: Undoing changes made to other modules or system parameters during your module’s installation.
  • Dropping custom database tables or columns: If your module created database structures outside of Odoo’s ORM (e.g., via cr.execute in a pre-init hook), you should clean them up here.
  • Dependency cleanup: Performing actions related to other modules that might be affected by your module’s removal.
Implementing an uninstall_hook

Similar to the post_init_hook, an uninstall_hook function takes cr and registry as arguments.

Let’s illustrate with an example for Odoo Hooks Explained:

# In your module's Python file
from odoo import api, SUPERUSER_ID

def _third_uninstall_hook(cr, registry):
    print("Uninstall hook before uninstall module: Starting custom cleanup logic.")
    env = api.Environment(cr, SUPERUSER_ID, registry)

    # Example 1: Reset VAT for partners that were set by the post_init_hook
    # This uses direct SQL as shown in the context.
    cr.execute("""UPDATE res_partner SET vat='' WHERE vat='12345'""")
    cr.commit() # Commit the direct SQL change
    print("Uninstall hook: VAT reset for partners with VAT '12345' using SQL.")

    # Example 2: Perform other cleanup tasks using ORM
    # For instance, if your module created specific configuration parameters:
    # config_param = env['ir.config_parameter'].sudo().search([('key', '=', 'my_module.my_setting')])
    # if config_param:
    #     config_param.unlink()
    #     print("Uninstall hook: Removed custom ir.config_parameter 'my_module.my_setting'.")

    # Example from context: Call a hook_method, perhaps for further specific cleanup
    if hasattr(env['res.partner'], 'hook_method'):
        print("Uninstall hook: Attempting to call hook_method on res.partner for cleanup.")
        env['res.partner'].hook_method() # Assuming this method handles its own logic for uninstallation context
        print("Uninstall hook: Called hook_method on res.partner.")
    else:
        print("Uninstall hook: hook_method not found on res.partner.")
    print("Uninstall hook execution finished.")

In _third_uninstall_hook, the primary goal is to revert changes or clean up. The example shows resetting the VAT numbers that were previously set, using cr.execute. It also conceptually mentions removing custom configuration parameters using the ORM, which is a common cleanup task. The call to hook_method suggests that complex, model-specific cleanup logic can also be invoked.

Post-Load Hooks (post_load or _register_hook): Actions After Server Startup and Module Loading

The post_load hook (sometimes referred to or implemented via _register_hook for more dynamic modifications) is different from the init/uninstall hooks. It executes when the Odoo server starts up, after all modules (including the current one) have been loaded into the registry.

Purpose and Use Cases for Post-Load Hooks

These hooks are powerful and used for:

  • Dynamic model modification: You can add fields to existing models, change attributes of fields, or even dynamically create new models, although this is advanced and should be used carefully.
  • Method overriding (monkey patching): You can replace or extend methods of existing Odoo models across any module. This is a common way to customize core Odoo behavior or behavior from other third-party apps.
  • Adding custom constraints: You can programmatically add Python constraints to models.
  • Registering custom report types or other system-level extensions.
Implementing a post_load hook

A post_load hook is typically a function that takes no arguments. It’s called once the Odoo server has loaded all module code.

Here’s a conceptual example, as the context provides a simple print statement:

# In your module's Python file

# This function will be called after all modules are loaded
def _my_post_load_hook():
    print("Post-load hook: Executing after all modules are loaded.")
    # Example: Dynamically add a method to an existing model (Monkey Patching)
    # from odoo.addons.contacts.models.res_partner import Partner
    #
    # def new_custom_method(self):
    #     print(f"Hello from new_custom_method on partner {self.name}!")
    #     return True
    #
    # Partner.new_custom_method = new_custom_method
    # print("Post-load hook: Dynamically added 'new_custom_method' to res.partner.")

    # The context shows a commented-out section related to WebRequest.set_handler
    # This suggests potential use for modifying web request handling,
    # which is an advanced use case for post_load hooks.
    # For example:
    # from odoo.http import WebRequest
    # original_set_handler = WebRequest.set_handler
    #
    # def custom_set_handler(self, *args, **kwargs):
    #     print("Custom set_handler called!")
    #     return original_set_handler(self, *args, **kwargs)
    #
    # WebRequest.set_handler = custom_set_handler
    # print("Post-load hook: Patched WebRequest.set_handler.")
    print("Post-load hook execution finished.")

# The context uses '_post_load_hook' as the function name for registration.
_post_load_hook = _my_post_load_hook

_post_load_hook = _my_post_load_hook The _my_post_load_hook example here conceptually shows how you might perform monkey patching to add a new method to the res.partner model or modify web request handling. The key is that these operations occur after all code is loaded, allowing you to inspect and modify the live Odoo environment. This is a powerful feature when Odoo Hooks Explained in depth.

Registering Hooks in the __manifest__.py File

To make Odoo aware of your hook functions, you must declare them in your module’s __manifest__.py file. You specify the name of your Python function (as a string) for each corresponding hook key.

Based on the provided context, the manifest registration looks like this:

# In your module's __manifest__.py
{
    'name': 'My Custom Module with Hooks',
    'version': '1.0',
    'summary': 'Demonstrates Odoo lifecycle hooks.',
    'author': 'Your Name',
    'website': 'https://www.yourwebsite.com',
    'category': 'Uncategorized',
    'depends': ['contacts'], # Example dependency
    'data': [
        'security/ir.model.access.csv',
        # 'views/student_views.xml', # Example view file
    ],
    'demo': [],
    'installable': True,
    'application': False,
    'auto_install': False,
    # Hook registration
    'pre_init_hook': '_first_pre_init_hook',   # Points to the function in your Python code
    'post_init_hook': '_second_post_init_hook', # Points to the function
    'uninstall_hook': '_third_uninstall_hook', # Points to the function
    'post_load': '_post_load_hook',           # Points to the function (can also be _register_hook for some uses)
}
  • pre_init_hook is set to '_first_pre_init_hook', meaning Odoo will look for a function named _first_pre_init_hook in your module’s Python files (typically __init__.py or a dedicated hooks.py imported in __init__.py).
  • Similarly, post_init_hook, uninstall_hook, and post_load are mapped to their respective function names.

It’s crucial that these function names in the manifest string exactly match the function names defined in your Python code.

Best Practices and Important Considerations for Odoo Hooks

When working with Odoo custom logic hooks, keep the following best practices in mind:

  1. Idempotency: Ensure your hooks are idempotent. This means running them multiple times should not have unintended side effects or cause errors. This is especially important for post_init_hook if a module installation is retried.
  2. Use ORM When Possible: In post_init_hook and uninstall_hook, prefer using the Odoo ORM (env[...]) over raw SQL (cr.execute) when your module’s models are involved. The ORM respects model constraints, workflows, and related field computations. Raw SQL is better suited for pre_init_hook or when dealing with schema changes or performance-critical bulk operations where models are not yet fully available or would be too slow.
  3. cr.commit() Usage: Be cautious with cr.commit(). Odoo typically manages transactions around hooks. If a hook fails, Odoo attempts to roll back the changes. Committing mid-hook can lead to inconsistent data if a subsequent operation in the same hook (or the main installation process) fails. The context examples use cr.commit() after cr.execute(). This is acceptable if each SQL operation is atomic and intended to be final, but understand the implications.
  4. SUPERUSER_ID: Hooks often run with SUPERUSER_ID to bypass access rights, as they perform administrative tasks. This is generally fine, but be aware of the security implications if you are manipulating data based on user input passed to the hook (which is rare).
  5. Error Handling: Implement robust error handling within your hooks. Use try...except blocks to catch potential exceptions and log them clearly. A failing hook can halt the entire module installation, upgrade, or uninstallation process.

Important Considerations for Odoo Hooks

  1. Performance: Be mindful of performance, especially in post_init_hook if you are processing large amounts of data. Optimize your ORM queries or SQL statements.
  2. Modularity: Keep hook logic focused on the module it belongs to. Avoid overly broad changes to other parts of the system unless absolutely necessary and well-documented.
  3. Testing: Thoroughly test your hooks under various scenarios: fresh installation, re-installation, uninstallation, and module upgrade (if your hook logic also needs to cater to upgrades, which often involves version checking within the hook).
  4. hook_method() Example: The context refers to env['res.partner'].hook_method(). This implies a custom method defined on the res.partner model (either in this module or a dependency). Such methods can encapsulate complex logic specific to the model, making the hook functions themselves cleaner and more readable. For example, hook_method could prepare partner data in pre_init, finalize it in post_init, and clean it up in uninstall.

Conclusion: Leveraging Odoo Hooks for Robust Modules

Odoo Hooks Explained provides developers with a powerful and flexible way to manage the lifecycle of their modules. By injecting custom Python code at critical stages—before installation, after installation, before uninstallation, and after server load—you can automate complex setups, manage data migrations, ensure clean uninstalls, and dynamically modify Odoo’s behavior. Understanding the purpose and correct implementation of pre_init_hook, post_init_hook, uninstall_hook, and post_load hooks is essential for building robust, maintainable, and professional Odoo applications.

Remember to always test your hooks thoroughly and follow best practices to ensure they enhance, rather than complicate, your Odoo development workflow. For more advanced scenarios or specific Odoo version details, always refer to the official Odoo Developer Documentation. Happy hooking!


Discover more from teguhteja.id

Subscribe to get the latest posts sent to your email.

Leave a Reply

WP Twitter Auto Publish Powered By : XYZScripts.com