Một câu đố khiến người mới bối rối: mở res.users ra, bạn đọc được user.name, user.email, user.phone. Nhưng nhìn vào database, bảng res_users không có cột name. Vậy user.name lấy ở đâu ra? Câu trả lời là một cơ chế kế thừa đặc biệt của Odoo: _inherits (chú ý chữ "s" ở cuối). Nó khác hẳn _inherit ở bài trước, và hiểu nhầm hai cái là nguồn của rất nhiều lú lẫn.
_inherits: nối hai model qua một Many2one
_inherits khai báo dưới dạng {model_cha: 'field_liên_kết'}. Ví dụ kinh điển là chính res.users:
class Users(models.Model):
_name = 'res.users'
_inherits = {'res.partner': 'partner_id'} # uỷ quyền sang partner
partner_id = fields.Many2one('res.partner', required=True, ondelete='restrict')
Ý nghĩa: mỗi res.users giữ một liên kết partner_id tới một res.partner, và Odoo cho phép user "mượn" (delegate) mọi field của partner qua liên kết đó. user.name thật ra là user.partner_id.name — Odoo tự chuyển hướng.

Hình 1: _inherits = {'res.partner': 'partner_id'}. Field partner_id là mắt xích. Mọi field của partner (name, email, phone...) truy cập được trực tiếp trên user, nhưng dữ liệu thật nằm ở bản ghi partner được liên kết. ondelete='restrict' bảo vệ: không cho xoá partner khi còn user trỏ vào.
Chứng minh trên hệ thống thật
Chạy odoo shell để thấy cơ chế lộ ra:

Hình 2: Ba điều cốt lõi hiện rõ. (1) Cột name không nằm ở bảng res_users — nó ở res_partner; user chỉ mượn. (2) Tạo user tự sinh partner: số partner tăng 31→32, và user id 9 nối tới partner id 3549 — hai bản ghi, hai bảng. (3) Ghi xuyên qua: gán u.name='Da Doi Ten' thì partner.name đổi theo. Lưu ý cuối: xoá user thì partner vẫn còn — quan hệ một chiều, partner sống độc lập.
_inherits vs _inherit: đừng nhầm chữ "s"
Đây là bảng phân biệt để không bao giờ lẫn nữa:
_inherit = ['ten.model'](không "s"): mở rộng hoặc trộn. Nếu kèm_namemới → trộn mixin (bài 53); nếu không kèm_name→ mở rộng chính model đó. Không tạo bảng liên kết; field nằm chung một bảng._inherits = {'ten.model': 'field_id'}(có "s"): uỷ quyền (delegation). Hai model có hai bảng riêng, nối nhau qua một Many2one; model con mượn field của model cha nhưng dữ liệu ở hai nơi.
Cách nhớ: _inherit là "tôi là một dạng của nó" (kế thừa kiểu OOP); _inherits là "tôi có một cái đó và mượn đồ của nó" (kết hợp qua liên kết).
Khi nào dùng _inherits
- Khi một thực thể là sự mở rộng của thực thể khác nhưng cần bảng riêng. User là một partner có thêm khả năng đăng nhập; sản phẩm bán (
product.product) uỷ quyền sang mẫu sản phẩm (product.template). Dùng_inheritsđể không chép lại toàn bộ field. - Khi muốn tạo con là tự động có cha.
createtrên model con với các field của cha sẽ tự tạo bản ghi cha — tiện và nhất quán.
Vài lưu ý thực chiến:
- Field liên kết phải
required=True(mỗi user phải có một partner). Thường đặtondelete='restrict'hoặccascadetuỳ ngữ nghĩa. - Xoá con không tự xoá cha (như thấy: xoá user, partner còn) — cha có thể được chia sẻ hoặc tồn tại độc lập. Nếu muốn dọn cha, phải làm tay.
- Chỉ uỷ quyền được field, không uỷ quyền method theo cách tự động như field — muốn gọi method của cha thì qua
record.partner_id.method().
Ba ý mang về
_inherits = {'model_cha': 'field_id'}nối model con vào model cha qua một Many2one; con mượn toàn bộ field của cha (đọc/ghi xuyên qua), nhưng dữ liệu nằm ở hai bảng riêng. Đã chứng minh: cộtnamekhông ởres_usersmà ởres_partner.- Tạo con tự sinh cha:
createmột user vớiname/emaillàm số partner tăng 31→32; ghiu.nameđổi luônpartner.name. Xoá con không tự xoá cha. - Đừng nhầm với
_inherit(không "s"):_inherittrộn/mở rộng trong cùng bảng;_inheritsuỷ quyền qua liên kết giữa hai bảng. "Là một" vs "có một".
Ta đã đi hết các kiểu kế thừa model. Lần sau bước vào chỗ dễ sai nhất khi tuỳ biến hành vi model: Phần sau nói về ghi đè create/write/unlink đúng cách — gọi super() ở đâu, xử lý batch ra sao, và những cái bẫy khiến dữ liệu sai âm thầm.