Many2one vs One2many in Odoo 18
By Braincuber Team
Published on January 15, 2026
At the heart of Odoo's powerful framework lies its Object-Relational Mapping (ORM) system, which allows different business models to interact seamlessly. Whether you're connecting a Sale Order to a Customer or linking multiple Order Lines to a single Quotation, understanding relational fields is non-negotiable for any Odoo developer.
Two of the most frequently used relationship types are Many2one and One2many. While they often work in tandem, they serve distinct purposes in database architecture and user interface design. In this guide, we'll break down the differences using a practical University Management example—linking Students to Departments.
Quick Summary:
- Many2one: The "Parent" link. Stores a foreign key in the database. (e.g., A Student belongs to one Department).
- One2many: The "Children" view. Virtual field, no database column. (e.g., A Department has many Students).
- Relationship: One2many cannot exist without a corresponding Many2one field.
1. Understanding Many2one (The Foundation)
A Many2one field creates a link where many records of the current model relate to one record of a target model (co-model).
Real-World Analogy
Think of a Student. Thousands of students study at a university, but each specific student belongs to only one Department (e.g., Computer Science).
- Source Model: Student
- Target Model: Department
- Logic: Many students -> One Department.
Database Perspective
When you define a Many2one field, Odoo creates a physical column in the database table (e.g., department_id) that stores the integer ID of the related record. It acts as a standard SQL Foreign Key.
Code Implementation
from odoo import models, fields
class UniversityStudent(models.Model):
_name = 'university.student'
_description = 'University Student'
name = fields.Char(string='Name', required=True)
# Many2one Field: Links student to a department
department_id = fields.Many2one(
comodel_name='university.department',
string='Department',
ondelete='set null',
help="The department this student belongs to."
)
2. Understanding One2many (The Inverse)
A One2many field allows one record to view many related records. It is essentially a "window" to see all records that point back to it via a Many2one field.
Real-World Analogy
Think of the Department. The "Computer Science" department isn't just a building; it is a collection of all the students enrolled in it.
- Source Model: Department
- Target Model: Student
- Logic: One Department -> Many Students.
Database Perspective
Crucial Distinction: A One2many field does NOT create a column in the database table of the source model. It is a virtual relationship. It relies entirely on the existence of a Many2one field in the related model to reverse-lookup the data.
Code Implementation
from odoo import models, fields
class UniversityDepartment(models.Model):
_name = 'university.department'
_description = 'University Department'
name = fields.Char(string='Department Name', required=True)
# One2many Field: Lists all students in this department
# 'inverse_name' MUST match the Many2one field name in the student model
student_ids = fields.One2many(
comodel_name='university.student',
inverse_name='department_id',
string='Enrolled Students'
)
Key Similarities & Differences
| Feature | Many2one | One2many |
|---|---|---|
| Database Storage | Yes (Stores Integer ID) | No (Virtual Field) |
| Mandatory Params | comodel_name |
comodel_name, inverse_name |
| Dependency | Independent | Requires a Many2one inverse |
| Default Widget | Dropdown / Autocomplete | List View (X2Many) / Kanban |
3. UI Implementation
Defining the python code is only half the battle. Here is how these fields differ when added to XML views.
Many2one in Form View
<!-- Student Form View -->
<field name="name"/>
<field name="department_id" options="{'no_create': True, 'no_open': True}"/>
Tip: Use options to prevent users from creating new departments on the fly.
One2many in Form View
<!-- Department Form View -->
<field name="name"/>
<notebook>
<page string="Students">
<field name="student_ids">
<tree editable="bottom">
<field name="name"/>
<!-- department_id is hidden implies context is passed automatically -->
</tree>
</field>
</page>
</notebook>
Frequently Asked Questions
ondelete parameter set on the Many2one field in the related model.
cascade: All related records (students) are deleted.set null: The link is removed, but records remain (students become department-less).restrict: Prevents deletion of the parent if children exist.
inverse_name parameter. If it points to the wrong Many2one field (or one that doesn't exist), Odoo cannot link the records. Also, ensure the User Access Rights allow reading those specific records.
