When building Odoo modules, you'll often find yourself repeating the same fields or methods across multiple models — things like audit timestamps, approval workflows, or status tracking. Abstract models let you define this logic once and reuse it everywhere, keeping your code DRY and maintainable.
What is an Abstract Model?
In Odoo, there are three types of models:
- models.Model — A regular model stored in the database
- models.TransientModel — A temporary model (used in wizards)
- models.AbstractModel — A blueprint model, not stored in the database
Abstract models are never instantiated on their own. They exist purely to be inherited by other models, sharing their fields and methods without creating a database table.
A Simple Example: Adding Audit Fields
Say you want every model in your app to track who created a record and when it was last updated. Instead of adding fields to each model, define an abstract model:
from odoo import models, fields
class AuditMixin(models.AbstractModel):
_name = 'mixin.audit'
_description = 'Audit Mixin'
created_by = fields.Char(string='Created By', readonly=True)
last_updated = fields.Datetime(string='Last Updated', readonly=True)
def write(self, vals):
vals['last_updated'] = fields.Datetime.now()
return super().write(vals)
def create(self, vals):
vals['created_by'] = self.env.user.name
return super().create(vals)
class ApprovalMixin(models.AbstractModel):
_name = 'mixin.approval'
_description = 'Approval Workflow Mixin'
state = fields.Selection([
('draft', 'Draft'),
('submitted', 'Submitted'),
('approved', 'Approved'),
('rejected', 'Rejected'),
], string='Status', default='draft')
def action_submit(self):
self.state = 'submitted'
def action_approve(self):
self.state = 'approved'
def action_reject(self):
self.state = 'rejected'
Now, any model can inherit this mixin:
from odoo import models
class SaleOrderCustom(models.Model):
_name = 'sale.order.custom'
_inherit = ['mixin.audit']
_description = 'Custom Sale Order'
That's it. Your sale.order.custom model now automatically has created_by, last_updated, and the override logic — no copy-pasting needed.
Using Multiple Mixins
One of the best parts? You can stack multiple abstract models using _inherit as a list:
class ExpenseClaim(models.Model):
_name = 'hr.expense.claim'
_inherit = ['mixin.audit', 'mixin.approval']
_description = 'Expense Claim'
Summary
Abstract models are one of Odoo's most underused features. They let you write shared logic once and compose it across many models cleanly. Start small — extract just one repeated pattern into a mixin — and you'll quickly see how much cleaner your codebase becomes.
