Odoo models (models.Model) have a variety of class attributes that define how the model behaves, how it’s stored, displayed, or interacted with in the system. Here’s a detailed explanation of all important class attributes, with examples and use cases.
1._name – Model Name (Mandatory for Custom Models)
- Purpose: Defines the technical name of the model in the database.
- Default models like
res.partneralready have_name. - Required for new custom models.
Example:
class MyEmployee(models.Model):
_name = 'my.employee'
name = fields.Char(string="Employee Name")- Table created in PostgreSQL:
my_employee - Use
_nameto refer to this model in relations like many2one.
2._inherit – Inherit an Existing Model
- Purpose: Extend or override an existing model.
- Can be used with or without
_name.
Example – Extend res.partner
class PartnerInherit(models.Model):
_inherit = 'res.partner'
employee_code = fields.Char(string="Employee Code")- Adds a new field to existing
res.partner. - No new table is created.
Example – Inherit + Rename Table (Rare)
class NewPartner(models.Model):
_name = 'new.partner'
_inherit = 'res.partner'Creates a new table but reuses fields from res.partner.
3._description – Model Description
- Purpose: Human-readable description of the model
- Appears in UI headers, documentation, and list views
class MyEmployee(models.Model):
_name = 'my.employee'
_description = "Employee Management System"
name = fields.Char()Optional but good practice for clarity.
4._rec_name – Record Display Name
Field used as display name in dropdowns, many2one, Kanban cards, etc.
rec_name is a special class attribute of a model that tells Odoo which field should be used as the "display name" for records
By default:
- Odoo uses the field
nameas therec_nameif it exists. - If your model doesn’t have a
namefield, you must explicitly definerec_name, otherwise the record will appear asrecord id: 1.
Syntax:
class MyModel(models.Model):
_name = 'my.model'
_rec_name = 'custom_name_field' # This is the important partExample 1 – Default name field
from odoo import models, fields
class Employee(models.Model):
_name = 'my.employee'
name = fields.Char(string="Full Name")
email = fields.Char(string="Email")- Here,
rec_nameis implicitlyname - Anywhere you select an employee (many2one field), Odoo shows the value of
name
Example 2 – Custom rec_name
from odoo import models, fields
class Employee(models.Model):
_name = 'my.employee'
_rec_name = 'email' # Use email as display name
first_name = fields.Char()
last_name = fields.Char()
email = fields.Char()- Now, in a dropdown or many2one field, records are displayed as email addresses instead of the default
name(which doesn’t exist here). - Useful if your model doesn’t have a
nameor you want to show something else.
Example 3 – Using a computed field as rec_name
from odoo import models, fields, api
class Employee(models.Model):
_name = 'my.employee'
_rec_name = 'full_name'
first_name = fields.Char()
last_name = fields.Char()
full_name = fields.Char(compute='_compute_full_name')
@api.depends('first_name', 'last_name')
def _compute_full_name(self):
for rec in self:
rec.full_name = f"{rec.first_name or ''} {rec.last_name or ''}".strip()- Here,
full_nameis a computed field - Records in a many2one field will show as
"First Last" - Very common in HR, Contacts, and Employee models
Where rec_name is used
Many2one fields
employee_id = fields.Many2one('my.employee', string="Employee")Shows
rec_nameof selected employee- Search views & filters
- Related widgets (Kanban, Form headers, etc.)
- Automatically generated references in Odoo logs
Advanced – Dynamic _rec_name with name_get
_rec_name only points to a single field, but if you want more dynamic display logic, override name_get.
class Employee(models.Model):
_name = 'my.employee'
first_name = fields.Char()
last_name = fields.Char()
department_id = fields.Many2one('hr.department')
def name_get(self):
result = []
for rec in self:
name = f"{rec.first_name} {rec.last_name}"
if rec.department_id:
name += f" ({rec.department_id.name})"
result.append((rec.id, name))
return resultResult:
- Shows
John Doe (IT Department)in many2one fields - Can include status, code, or any condition dynamically
5._order – Default Sorting
- Purpose: Define default sorting order for records
- Format:
'field_name asc|desc, field2 asc|desc'
class MyEmployee(models.Model):
_name = 'my.employee'
_order = 'joining_date desc, name asc'
name = fields.Char()
joining_date = fields.Date()- Records will be sorted by joining_date descending first, then name ascending.
6._table – Database Table Name
- Purpose: Explicitly set the table name in the database.
- By default, table name =
_namewith dots replaced by_.
class MyEmployee(models.Model):
_name = 'my.employee'
_table = 'company_employee'- Table in PostgreSQL:
company_employee - Useful when migrating legacy databases.
7._auto – Automatic Table Creation
- Purpose: Control if Odoo should create a database table for this model
- Default:
True False? Useful for abstract models, views, or transient models.
class MyAbstractModel(models.Model):
_name = 'my.abstract'
_auto = False # No table is created
8._inherits – Delegation Inheritance
- Purpose: Use fields from another model in a composition manner
- Unlike
_inherit(extension),_inheritscreates a relation rather than modifying existing table
class MyEmployee(models.Model):
_name = 'my.employee'
_inherits = {'res.partner': 'partner_id'}
partner_id = fields.Many2one('res.partner', required=True)
employee_code = fields.Char()- The table stores only
employee_code+partner_id - Accessing employee fields automatically delegates to
res.partner.
9._transient – Transient / Wizard Models
- Usually:
TransientModelinstead ofModel - Automatically cleaned after a few hours
- No permanent data storage.
class MyWizard(models.TransientModel):
_name = 'my.wizard'
_description = "Wizard Example"
start_date = fields.Date()
end_date = fields.Date()
10._log_access – Audit Fields
- Default:
True(createscreate_uid,create_date,write_uid,write_date) - Set to
Falseif you don’t want automatic tracking (rare)
class MyModel(models.Model):
_name = 'my.model'
_log_access = False11._check_company – Multi-Company Validation
- Default:
False - If
True, enforces company_id consistency on record creation and updates.
class MyEmployee(models.Model):
_name = 'my.employee'
_check_company = True
