In Odoo 19, the backbone of every business module — whether Sales, Inventory, or HR — is the model. Models define how data is structured, related, and processed across the system. For developers, mastering models means gaining control over the entire Odoo ORM (Object Relational Mapping) layer, which translates Python code into efficient SQL queries while managing security, caching, and business logic automatically.
This blog provides a technical deep-dive into how models work in Odoo 19, what’s new in this version, and how to design robust, upgrade-safe, and performant business logic.
In Odoo, a model represents a data structure (a table in the PostgreSQL database), plus the logic associated with it. Every model inherits from models. Model or its variants. The ORM automatically creates the database table, handles relationships, validation, and allows you to manipulate data using Python instead of writing SQL queries.
In Odoo, you build models by inheriting from one of these base classes:
- RegularModel – used for standard models whose records are permanently stored in the database.
- TransientModel – used for temporary records (like wizard data). These are saved in the database but automatically cleaned up after some time.
- AbstractModel – used to define shared behavior. These models don’t create database tables by themselves, but other models can inherit from them.
For every database, Odoo automatically creates an instance of each model. These instances reflect the models available based on the modules installed in that database. The final model that Odoo uses is assembled from all Python classes that define or extend that model through inheritance.
Models
Models are defined within the /models directory of your custom Odoo module. A basic model definition requires the mandatory _name attribute, which uniquely identifies the model in the system, and a _description:
from odoo import models, fields
class EstateProperty(models.Model):
_name = 'estate.property'
_description = 'Real Estate Property'
name = fields.Char(required=True)
price = fields.Float()
When defining some models like this, Odoo automatically:
- Creates and manages a corresponding database table
- Maps fields to PostgreSQL columns
- Generates CRUD operations (create, read, update, delete)
- Handles domain filters, constraints, and security
- Provides multi-company & multi-user behavior
- Integrates with views, XML data, access rules, wizards, and reports
Odoo’s model system is both simple to use and extremely powerful.
Model Attributes
Models are defined with special attributes that control their behavior:
- _name : The unique technical identifier for the model (e.g., 'project.task'). This value is used for relationships (Many2one, etc.) and forms the basis of the database table name (_).
- _description : A user-friendly, descriptive label for the model, used primarily in the UI.
- _auto : If set to False, the ORM will not automatically create or update the corresponding database table based on the model definition. Used primarily for custom models that map to existing external tables.
- _table : Database table name (defaults to _name with dots replaced by underscores)
- _rec_name: The name of the field that will be used as the primary display name for records in this model (e.g., in Many2one drop-downs). Defaults to 'name' field in the model.
- _order : Defines the default sorting criteria for records retrieved from this model (e.g., 'name asc', 'create_date desc').
- _log_access : If set to True (the default), Odoo automatically adds tracking fields: create_uid, create_date, write_uid, and write_date. Setting it to False disables this logging.
- _abstract : If set to True, the model is an abstract model (it doesn't inherit from models.AbstractModel but functions similarly). It won't create a database table, but can be inherited by other concrete models.
- _transient : If set to True (or if inheriting from models.TransientModel), records are automatically deleted by a scheduled cron job after a period of inactivity.
- _inherit : Used for classical inheritance (extension). It extends an existing model by adding new fields and methods to the original database table.
- _inherits : Used for delegation inheritance. It links the current model to others in a one-to-one fashion, allowing the current model to access the fields of the inherited models directly. Format: {'model.name': 'field_id'}.
- _active_name : Field to use for active records, automatically set to either ``"active"`` or ``"x_active"``.
- _fold_name : Field to determine folded groups in kanban views
Fields
Fields are used to define what the model can store and where they are stored. Fields are defined as attributes in the model class as follows:
class EstateProperty(models.Model):
_name = 'estate.property'
_description = 'Real Estate Property'
_order = 'price desc'
_rec_name = 'name'
name = fields.Char()
date = fields.Date()
Odoo provides a rich field system that supports:
- Simple Fields
- Relational Fields
- Advanced Fields
These fields store simple, direct values inside a database column. They are used to capture primitive data such as text, numbers, dates, or boolean flags. Basic fields map directly to PostgreSQL column types, making them lightweight and efficient.
Examples of what basic fields represent:
- Short or long text (names, descriptions, notes)
- Numeric values (quantities, amounts, percentages)
- Dates and timestamps (start date, invoice date)
- Toggle states (active/inactive)
These fields are the foundation of most business objects and define the core attributes of a model.
Relational fields create links between models, allowing Odoo to represent complex business structures. Instead of storing raw values, these fields connect records across tables and define relationships like “belongs to,” “has many,” or “shares many.”
They are crucial in modeling:
- Customer: Orders
- Contracts : Payments
- Products : Categories
- Employees : Departments
These relationships allow Odoo’s ORM to automatically load related records, manage joins, and ensure data consistency. Relational fields give Odoo its modular, interconnected data structure; business entities are not isolated but tied together through logical relationships.
Advanced field types in Odoo 19 are used when a model needs to store more complex or special kinds of data. These fields go beyond basic text, numbers, or dates. They help manage things like files, images, rich text, currency values, or structured data such as settings and configurations. Instead of acting like simple database columns, advanced fields often work with other Odoo systems, like the attachment system for storing documents, the currency engine for handling amounts, or the HTML editor for formatted content. This allows models to support features that are more interactive and powerful. In simple terms, advanced fields make it possible for Odoo to handle real-life business needs such as documents, media, multi-currency transactions, and flexible data formats, giving developers more control and more tools to build rich applications.
Models in Odoo 19 form the structural and logical backbone of every business application built on the platform. By defining data, relationships, and behavior all within the model layer, Odoo creates a unified and highly expressive framework for building modular business systems. Whether a model stores simple text values, manages relational links across multiple apps, or powers advanced features like currency handling, file storage, and automated computations, it ensures that developers can focus on business logic while Odoo’s ORM handles the complexities of database interactions, security, and consistency.
Understanding how models work, along with the categories of fields and the advanced capabilities they provide, allows developers to design cleaner, more scalable, and more maintainable customizations. As Odoo 19 continues to push the boundaries of flexibility and performance, mastering models becomes an essential skill for building robust, integrated business solutions that can grow with an organization’s needs.
To read more about An Overview of Model Attributes in Odoo 18, refer to our blog, An Overview of Model Attributes in Odoo 18.