Elevate Your Odoo Development: Mastering Odoo Model Inheritance
Odoo Model Inheritance is a cornerstone of robust Odoo development, enabling developers to build highly flexible, scalable, and maintainable applications. Whether you’re customizing existing Odoo modules or developing new ones from scratch, a deep understanding of how models inherit, extend, and delegate functionality is absolutely essential. This comprehensive tutorial will guide you through the three primary patterns of Odoo Model Inheritance: Classical Inheritance, Extension, and Delegation. By the end, you’ll be equipped to choose the right strategy for any Odoo development challenge, ensuring your solutions are elegant and efficient.
We’ll explore each type with clear explanations, practical code examples, and step-by-step implementation instructions for Odoo 16/17/18/19 environments. Let’s dive in and unlock the full potential of your Odoo projects!
1. Classical Inheritance: Specializing Your Models
Classical Inheritance in Odoo is the fundamental object-oriented programming concept where a new model (the child or sub-model) derives properties and behaviors from an existing model (the parent or base model). Think of it as creating a more specialized version of a general concept. In Odoo’s ORM (Object-Relational Mapping) context, this means the child model inherits the table schema, fields, and methods from its parent. This is a powerful way to promote code reuse and establish clear hierarchical relationships between your data structures.
Why and When to Use Classical Inheritance?
You should consider Classical Inheritance when:
- You need to create a specialized version of an existing custom model. For instance, if you have a
Vehiclemodel and want to createCarandMotorcyclemodels that share common vehicle attributes but also have their own unique characteristics. - You want to reuse a significant amount of code and data structure from a base model without modifying the base model itself.
- You are building a complex data hierarchy where sub-models naturally fit under a broader category.
Code for Models (Inheritance0 and Inheritance1)
This code demonstrates how Inheritance1 inherits from Inheritance0 using the _inherit class attribute, effectively showcasing Odoo Model Inheritance in action.
from odoo import models, fields, api
class Inheritance0(models.Model):
_name = 'inheritance.0'
_description = 'Inheritance Zero - Parent Model'
name = fields.Char(string="Name")
common_property = fields.Char(string="Common Property", default="Default Value")
def call(self):
"""A method to demonstrate calling inherited methods."""
return self.check("model 0")
def check(self, s):
"""This method is inherited by Inheritance1."""
return "This is {} record {} with common property: {}".format(s, self.name, self.common_property)
class Inheritance1(models.Model):
# '_inherit' links this model to 'inheritance.0'
# 'inheritance.0' here is the technical name of the model being inherited from.
_inherit = 'inheritance.0'
_description = 'Inheritance One - Child Model'
# 'name' and 'common_property' fields are automatically inherited.
# We can add new fields specific to Inheritance1
specific_field = fields.Integer(string="Specific Value", default=100)
# The call() method will be overridden, but check() remains inherited.
def call(self):
"""Overrides the parent's call method."""
return self.check("model 1") + " (specific: {})".format(self.specific_field)
@api.model
def create_and_test_classical_inheritance(self):
"""Helper method to test classical inheritance."""
self.env['inheritance.0'].search([]).unlink() # Clean up previous test records
self.env['inheritance.1'].search([]).unlink()
record_0 = self.env['inheritance.0'].create({'name': 'Parent Record A', 'common_property': 'Parent-specific'})
record_1 = self.env['inheritance.1'].create({'name': 'Child Record B', 'specific_field': 200})
print(f"Parent Record Call: {record_0.call()}")
print(f"Child Record Call: {record_1.call()}")
print(f"Child Record Inherited Name: {record_1.name}")
print(f"Child Record Specific Field: {record_1.specific_field}")
# Expected Output:
# Parent Record Call: This is model 0 record Parent Record A with common property: Parent-specific
# Child Record Call: This is model 1 record Child Record B with common property: Default Value (specific: 200)
# Child Record Inherited Name: Child Record B
# Child Record Specific Field: 200
Steps to Implement in Odoo 16/17/18/19:
- Create a New Module: Start by creating a new Odoo module (e.g.,
my_inheritance_module). Ensure you have the standard module structure with__manifest__.py,models/,views/, etc. - Define Your Parent and Child Models: Inside your
modelsdirectory, create a Python file (e.g.,classical_inheritance.py). Paste theInheritance0andInheritance1code provided above into this file. Remember to includefrom odoo import models, fields, apiat the top. - Update
__init__.py: In yourmodels/__init__.pyfile, ensure you import your new model file:from . import classical_inheritance. - Configure
__manifest__.py: Update your module’s__manifest__.pyfile to include the new Python file and setbaseas a dependency:
{
'name': 'My Inheritance Module',
'version': '1.0',
'summary': 'Demonstrates Odoo Model Inheritance patterns',
'description': """
This module showcases Classical Inheritance, Extension, and Delegation in Odoo.
""",
'author': 'Your Name',
'website': 'https://www.yourwebsite.com',
'category': 'Technical',
'depends': ['base'],
'data': [
# 'security/ir.model.access.csv', # If you add specific access rights
# 'views/inheritance_views.xml', # If you create UI for these models
],
'application': False,
'installable': True,
'auto_install': False,
'license': 'LGPL-3',
}
- Install/Upgrade the Module: In your Odoo instance, go to Apps, update your app list, and then install (or upgrade if it’s an existing module)
My Inheritance Module. - Test the Inheritance: You can test the interaction by running the
create_and_test_classical_inheritancemethod from the Odoo shell or by creating records in the UI if you’ve added views. The output demonstrates howInheritance1reusesInheritance0‘s structure and methods while allowing for specialization.
Explanation of Classical Inheritance
Inheritance0defines the base structure withnameandcommon_propertyfields, pluscall()andcheck()methods._inherit = 'inheritance.0': This critical line inInheritance1tells Odoo to create a new, distinct database table forInheritance1, but to essentially copy the schema and methods frominheritance.0.Inheritance1is a sub-class ofInheritance0.Inheritance1automatically gains access toname,common_property, andcheck().- It then overrides
call()to provide its own behavior, demonstrating method overriding while still leveraging the inheritedcheck()method. Notice howInheritance1‘s records will have their ownidand_name(inheritance.1), separate frominheritance.0. This is the hallmark of true sub-classing.
2. Extension: Augmenting Existing Models
Extension, also known as modular inheritance or “prototype inheritance” in Odoo, is a highly frequent and practical form of Odoo Model Inheritance. Its purpose is to add new fields or methods to an existing model, rather than creating a brand new, separate model. This is crucial for customizing Odoo’s core functionalities (like res.partner, product.template, sale.order) without directly modifying their source code, ensuring cleaner upgrades and module compatibility.
Why and When to Use Extension?
Use Extension when:
- You need to add custom fields to an Odoo core model (e.g., adding a
customer_tierfield tores.partner). - You want to override or add new methods to an existing Odoo model’s logic.
- You are building a custom module that integrates closely with standard Odoo functionalities and requires modifications to their data or behavior.
- You aim to keep your customizations separate from Odoo’s core, facilitating upgrades.
Code for Models (Extension0 and Extension1)
Model Extension1 extends model Extension0 by adding a new field, showcasing how Odoo Model Inheritance can modify existing structures.
from odoo import models, fields, api
class Extension0(models.Model):
_name = 'extension.0'
_description = 'Extension Zero - Base Model'
name = fields.Char(string="Name", default="Base Name")
class Extension1(models.Model):
# _inherit and _name are the same as the model being extended.
# This is the key to extending an existing model's table schema.
_inherit = 'extension.0'
_name = 'extension.0' # Explicitly stating _name is 'extension.0' confirms the extension
_description = 'Extension One - Extends Base Model'
# Adding a new field to the existing 'extension.0' model's table
extended_description = fields.Char(string="Extended Description", default="Default Extended")
priority = fields.Selection([('low', 'Low'), ('medium', 'Medium'), ('high', 'High')],
string="Priority", default="medium")
@api.model
def create_and_test_extension(self):
"""Helper method to test model extension."""
self.env['extension.0'].search([]).unlink() # Clean up previous test records
record = self.env['extension.0'].create({'name': 'My Extended Item'})
print(f"Record Name: {record.name}")
print(f"Record Extended Description: {record.extended_description}")
print(f"Record Priority: {record.priority}")
# Expected Output:
# Record Name: My Extended Item
# Record Extended Description: Default Extended
# Record Priority: medium
Steps to Implement in Odoo 16/17/18/19:
- Use an Existing Module or Create a New One: You can add this code to your
my_inheritance_moduleor create a new module (e.g.,my_extension_module). - Define Your Extension Model: Inside your
modelsdirectory, create a Python file (e.g.,extension.py). Paste theExtension0andExtension1code. - Update
__init__.py: Ensure yourmodels/__init__.pyfile imports the new file:from . import extension. - Configure
__manifest__.py: If you created a new module, set up its__manifest__.pysimilar to the Classical Inheritance example. If adding tomy_inheritance_module, ensure yourmodels/extension.pyis included if you modified thedatalist. - Install/Upgrade the Module: Go to Apps, update your app list, and then install or upgrade your module.
- Test the Extension: Use the
create_and_test_extensionmethod from the Odoo shell. You’ll observe that creating a record inextension.0(the base model) now automatically includes the fields defined inExtension1(extended_description,priority).
Explanation of Extension
Extension0is the base model, defining anamefield._inherit = 'extension.0'AND_name = 'extension.0': This combination is the hallmark of extension. It tells Odoo: “Don’t create a new table. Instead, modify the existing table that corresponds to theextension.0model.”- The
extended_descriptionandpriorityfields are then physically added to the database table ofextension.0. Any existing or new records ofextension.0will automatically have these new fields. - This approach seamlessly integrates your custom additions into the target model, making it appear as if the fields were always part of the original definition. It’s the standard and recommended way to customize core Odoo models.
3. Delegation: Composing Models for Clean Data Structure
Delegation, enabled by the _inherits attribute, represents a powerful form of Odoo Model Inheritance focused on composition rather than strict inheritance. It allows one model to “delegate” the management of certain fields to another model. From the user’s perspective, these delegated fields appear to belong to the main model, but internally, Odoo manages a Many2One relationship to a separate record in the delegated model. This promotes clean data separation and modularity, especially for complex entities.
Why and When to Use Delegation?
Choose Delegation when:
- You have a complex object that can be naturally broken down into smaller, self-contained components. For example, a
Laptopcan delegate itsScreenandKeyboardproperties to separate models. - You want to promote a “composition over inheritance” approach, leading to more flexible and maintainable code.
- You need to reuse common components across different models without duplicating their fields.
- The delegated components might have their own lifecycle or be shared by other models (though typically in
_inherits, the delegated record is specific to the delegating record).
Code for Models (Screen, Keyboard, and Laptop)
The Laptop model delegates its display and input-related fields to Screen and Keyboard models, a prime example of effective Odoo Model Inheritance for complex objects.
from odoo import models, fields, api
class Screen(models.Model):
_name = 'delegation.screen'
_description = 'Screen Component'
size = fields.Float(string='Screen Size (Inches)', help="Diagonal size of the screen.")
resolution = fields.Char(string='Resolution', default='1920x1080')
class Keyboard(models.Model):
_name = 'delegation.keyboard'
_description = 'Keyboard Component'
layout = fields.Char(string='Layout', help="e.g., QWERTY, AZERTY")
backlit = fields.Boolean(string='Backlit', default=False)
class Laptop(models.Model):
_name = 'delegation.laptop'
_description = 'Laptop Device'
# Delegation configuration
# Maps delegated model's technical name to the Many2One field linking it.
_inherits = {
'delegation.screen': 'screen_id',
'delegation.keyboard': 'keyboard_id',
}
name = fields.Char(string='Laptop Name', required=True)
maker = fields.Char(string='Manufacturer')
processor = fields.Char(string='Processor', default='Intel Core i5')
# Many2One fields that explicitly connect Laptop to Screen and Keyboard.
# These are crucial for delegation management.
screen_id = fields.Many2one(
'delegation.screen',
string='Screen Details',
required=True,
ondelete='cascade', # Important: Deletes screen record when laptop is deleted
help="Links to the screen specifications for this laptop."
)
keyboard_id = fields.Many2one(
'delegation.keyboard',
string='Keyboard Details',
required=True,
ondelete='cascade', # Important: Deletes keyboard record when laptop is deleted
help="Links to the keyboard specifications for this laptop."
)
@api.model
def create_and_test_delegation(self):
"""Helper method to test model delegation."""
self.env['delegation.laptop'].search([]).unlink() # Clean up previous test records
self.env['delegation.screen'].search([]).unlink()
self.env['delegation.keyboard'].search([]).unlink()
# Create delegated records first
screen_record = self.env['delegation.screen'].create({'size': 15.6, 'resolution': '2560x1440'})
keyboard_record = self.env['delegation.keyboard'].create({'layout': 'QWERTY', 'backlit': True})
# Create the Laptop record, linking to the delegated components
laptop_record = self.env['delegation.laptop'].create({
'name': 'ProBook X1',
'maker': 'TechCorp',
'processor': 'AMD Ryzen 7',
'screen_id': screen_record.id,
'keyboard_id': keyboard_record.id,
})
print(f"Laptop Name: {laptop_record.name}")
print(f"Laptop Maker: {laptop_record.maker}")
print(f"Laptop Processor: {laptop_record.processor}")
# Accessing delegated fields directly:
print(f"Screen Size: {laptop_record.size} inches")
print(f"Screen Resolution: {laptop_record.resolution}")
print(f"Keyboard Layout: {laptop_record.layout}")
print(f"Keyboard Backlit: {laptop_record.backlit}")
# Expected Output:
# Laptop Name: ProBook X1
# Laptop Maker: TechCorp
# Laptop Processor: AMD Ryzen 7
# Screen Size: 15.6 inches
# Screen Resolution: 2560x1440
# Keyboard Layout: QWERTY
# Keyboard Backlit: True
Steps to Implement in Odoo 16/17/18/19:
- Use an Existing Module or Create a New One: Add this code to
my_inheritance_moduleor a new module (e.g.,my_delegation_module). - Define Your Delegated and Delegating Models: Inside your
modelsdirectory, create a Python file (e.g.,delegation.py). Paste theScreen,Keyboard, andLaptopmodel code. - Update
__init__.py: Ensure yourmodels/__init__.pyfile imports the new file:from . import delegation. - Configure
__manifest__.py: Update your module’s__manifest__.pyif necessary. - Install/Upgrade the Module: Install or upgrade your module.
- Test the Delegation: Run the
create_and_test_delegationmethod from the Odoo shell. Observe how you can accesssize,resolution,layout, andbacklitdirectly through thelaptop_recordobject, even though they belong to separateScreenandKeyboardrecords.
Explanation of Delegation
_inherits: This is a dictionary where keys are the technical names of the models being delegated to ('delegation.screen','delegation.keyboard'), and values are the names of theMany2onefields ('screen_id','keyboard_id') in theLaptopmodel that link to these delegated records.screen_idandkeyboard_id: These are standardMany2onefields. When aLaptoprecord is created, newScreenandKeyboardrecords are often created and linked via theseMany2onefields.- Direct Field Access: The magic of
_inheritsis that it allowslaptop_record.sizeto directly fetch thesizefrom the linkedScreenrecord, andlaptop_record.layoutto fetch thelayoutfrom the linkedKeyboardrecord. Odoo’s ORM handles the underlying data redirection seamlessly. ondelete='cascade': This is a critical option for delegatedMany2onefields. It ensures that when aLaptoprecord is deleted, its associatedScreenandKeyboardrecords are also deleted, preventing orphaned data in your database.- Delegation offers a clean way to model “has-a” relationships (e.g., a Laptop has a Screen) while providing convenient access to sub-component properties.
Best Practices and Choosing the Right Odoo Model Inheritance Approach
Understanding the nuances of each Odoo Model Inheritance pattern is key to building maintainable and scalable Odoo applications. Here’s a quick guide and some best practices:
- Classical Inheritance (
_inheritcreates a new model/table):- When to use: To create specialized versions of your own custom base models.
- Benefits: Strong type hierarchy, code reuse, clear parent-child relationship.
- Caution: Avoid using it to customize Odoo core models directly, as it creates a separate table and won’t merge fields with the original. It can also lead to deep hierarchies that are hard to manage.
- Extension (
_inheritand_nameare the same):- When to use: The primary method for customizing and extending existing Odoo core models (e.g.,
res.partner,product.template) or custom models from other modules. - Benefits: Modifies the existing model’s table, adds fields/methods directly, ensures compatibility with Odoo upgrades, modular and clean.
- Caution: Can lead to very large models if too many modules extend the same core model. Ensure field names are unique to avoid conflicts.
- When to use: The primary method for customizing and extending existing Odoo core models (e.g.,
- Delegation (
_inherits):- When to use: When a complex model can be logically broken down into several distinct component models, and you want to manage these components separately but access their fields directly from the main model. Ideal for “has-a” relationships.
- Benefits: Promotes composition over inheritance, cleaner data structure, modularity, simplifies user interaction by exposing delegated fields directly.
- Caution: Requires careful management of
Many2onefields (especiallyondelete='cascade') and can add a slight overhead due to underlying joins for data access.
General Best Practices:
- Prioritize Extension for Core Models: Always use Extension when modifying standard Odoo models to ensure upgradability and module compatibility.
- Favor Composition (Delegation) for Complex Objects: When designing your own complex data models, consider if Delegation can lead to a cleaner, more modular structure than deep Classical Inheritance.
- Keep Models Focused: Each model should ideally represent a single concept. Don’t overload a single model with too many unrelated fields, regardless of the inheritance type.
- Document Your Design: Clearly document your inheritance choices within your code and module descriptions. Future developers (and your future self!) will thank you.
- Test Thoroughly: Always write tests for your inherited, extended, or delegated models to ensure they behave as expected.
By mastering these three forms of Odoo Model Inheritance, you gain incredible power and flexibility in Odoo development. This knowledge empowers you to build robust, maintainable, and highly customized Odoo solutions that can adapt and grow with your business needs. Happy coding!
External Resources for Further Learning:
- Odoo Documentation on Models – Official Odoo documentation on defining and interacting with models.
- Odoo Developer Tutorials – A great starting point for various Odoo development topics.
Internal Links (Placeholder):
- Explore More Odoo Development Guides on Our Blog
- Building Your First Odoo Module: A Step-by-Step Guide
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.

