Ở bài 194, các trường của model là dữ liệu đơn lẻ (chữ, số). Nhưng dữ liệu thật luôn liên kết: một thẻ thành viên thuộc về một khách, có nhiều lần tích điểm, và được áp nhiều ưu đãi. Odoo mô tả các mối nối đó bằng ba loại trường quan hệ. Nắm ba loại này là nắm phần "khó nhằn" nhưng quan trọng nhất khi lập trình Odoo.
Ba loại quan hệ

Hình 1: Ba trường quan hệ trên model thẻ. Many2one (partner_id): nhiều thẻ trỏ về một khách. One2many (lich_su_ids): một thẻ có nhiều dòng lịch sử điểm — nó là "mặt ngược" của Many2one the_id bên model con LichSuDiem. Many2many (uu_dai_ids): một thẻ có nhiều ưu đãi, và một ưu đãi cho nhiều thẻ.
Hiểu bản chất từng loại:
- Many2one ("nhiều-về-một"): lưu một khoá ngoại trỏ tới một bản ghi bảng khác. Ví dụ: mỗi thẻ ghi nó thuộc khách nào. Đây là quan hệ nền tảng nhất.
- One2many ("một-nhiều"): không tạo cột mới trong CSDL — nó chỉ là cách nhìn ngược của một Many2one. Thẻ "có nhiều lịch sử" chính vì mỗi dòng lịch sử có
the_idtrỏ ngược về thẻ. Cần khaithe_idbên kia thì One2many mới hoạt động. - Many2many ("nhiều-nhiều"): hai bên đều có thể có nhiều bên kia. Odoo tự tạo một bảng trung gian để lưu các cặp — bạn không phải làm gì thêm.
ondelete='cascade' ở the_id: xoá thẻ thì xoá luôn lịch sử điểm của nó — tránh dữ liệu mồ côi.
Cài vào Odoo — quan hệ thành giao diện
Điều đẹp nhất: khai xong quan hệ, Odoo dựng widget giao diện tương ứng. Mở form thẻ:

Hình 2: Cả ba quan hệ trên một form thật. Khách hàng (Many2one) là ô chọn một đối tác. Ưu đãi áp dụng (Many2many, widget many2many_tags) hiển thị nhiều thẻ tag — thêm/bớt thoải mái. Tab Lịch sử điểm (One2many) là một bảng con ngay trong form: 3 dòng tích điểm, nút "Thêm một dòng" để nhập trực tiếp. Dữ liệu con nằm gọn trong bản ghi cha.
Từ vài dòng khai báo, ta có ô chọn, tag, và bảng con nhập liệu — không viết một dòng giao diện phức tạp nào.
Chọn loại nào cho tình huống nào?
- Mỗi bản ghi thuộc về đúng một cái khác → Many2one (đơn hàng thuộc khách, dòng thuộc đơn).
- Một bản ghi sở hữu một danh sách con → One2many (đơn có nhiều dòng hàng) — nhớ có Many2one ngược bên model con.
- Hai bên nhiều-nhiều, không bên nào "sở hữu" → Many2many (sản phẩm có nhiều thẻ, khoá học có nhiều học viên).
Hầu hết model Odoo (kể cả Bán hàng, Kho) chỉ là các model nối nhau bằng đúng ba loại này.
Lưu ý khi dùng trường quan hệ
- One2many cần Many2one đối ứng — khai
One2many('model.con', 'ten_field_nguoc');ten_field_nguocphải tồn tại bên model con. ondeletetrên Many2one quyết định số phận khi bản ghi cha bị xoá:cascade(xoá theo),set null(bỏ trống),restrict(chặn xoá).- Many2many tự tạo bảng trung gian — không cần khai bảng đó; muốn đặt tên riêng thì thêm tham số.
- Đặt tên field theo quy ước: Many2one kết thúc
_id, One2many/Many2many kết thúc_ids— đọc code là biết loại.
Nhớ ba ý
- Many2one (
_id) lưu khoá ngoại "thuộc về một"; One2many (_ids) là mặt ngược của một Many2one ("có nhiều", không tạo cột mới); Many2many (_ids) là "nhiều-nhiều" (Odoo tự tạo bảng trung gian). - Khai quan hệ xong, Odoo dựng sẵn widget giao diện: ô chọn, tags, bảng con nhập liệu trong form.
- One2many cần Many2one đối ứng bên model con; dùng
ondeleteđể xử lý dữ liệu con khi xoá cha.
Còn một kỹ thuật mạnh nữa để tái dùng và mở rộng thứ có sẵn thay vì viết lại. Phần sau nói về kế thừa model và view (inherit) — thêm trường/sửa giao diện của app khác mà không đụng mã gốc.