Bạn có ba model cần cùng một thứ: một field "ghi chú nội bộ", một cờ "đã có ghi chú", và một hàm dán nhãn. Chép cùng một đoạn code vào ba nơi là công thức của bug và mệt mỏi. Odoo có cách gọn hơn: viết logic một lần trong một AbstractModel rồi trộn (mix) nó vào từng model bằng _inherit. Đây chính là cơ chế đứng sau những mixin trứ danh như mail.thread (theo dõi thay đổi) hay mail.activity.mixin.
Bài này tự dựng một mixin thật vào module quan_ca_phe và gắn nó vào model thẻ thành viên — để thấy tận mắt AbstractModel là gì và trộn vào hoạt động ra sao.
AbstractModel: model không có bảng
models.AbstractModel khai báo giống model thường (có field, method, computed) nhưng có một điểm khác căn bản: nó không sinh bảng trong database. Nó tồn tại chỉ để cho đi field và method cho các model khác kế thừa.
class DauVetMixin(models.AbstractModel): # AbstractModel, không phải Model
_name = 'quan.mixin.dau.vet'
_description = 'Mixin dấu vết ghi chú'
ghi_chu_noi_bo = fields.Text('Ghi chú nội bộ')
co_ghi_chu = fields.Boolean('Đã có ghi chú',
compute='_compute_co_ghi_chu', store=True)
@api.depends('ghi_chu_noi_bo')
def _compute_co_ghi_chu(self):
for rec in self:
rec.co_ghi_chu = bool(rec.ghi_chu_noi_bo and rec.ghi_chu_noi_bo.strip())
def dan_nhan(self, nhan): # method dùng lại cho mọi model mix vào
for rec in self:
rec.ghi_chu_noi_bo = ((rec.ghi_chu_noi_bo or '') + '\n') + '[%s]' % nhan

Hình 1: Trái tim của mixin. AbstractModel quan.mixin.dau.vet gói một field, một computed field và một method. Model thật quan.the.thanh.vien chỉ cần thêm một dòng _inherit = ['quan.mixin.dau.vet'] là nhận hết — không chép lại dòng code nào.
Trộn vào: chỉ một dòng _inherit
Để một model dùng mixin, thêm tên mixin vào _inherit:
class TheThanhVien(models.Model):
_name = 'quan.the.thanh.vien'
_inherit = ['quan.mixin.dau.vet'] # trộn mixin vào
# ... từ đây model có ghi_chu_noi_bo, co_ghi_chu, dan_nhan()
Sau khi nâng cấp module, mình chạy thử trên hệ thống thật để xác nhận model đã "hút" được mọi thứ từ mixin:

Hình 2: Chạy thật. Mixin có _abstract=True và không có bảng quan_mixin_dau_vet. Model quan.the.thanh.vien sau khi _inherit thì có đủ field ghi_chu_noi_bo, co_ghi_chu và method dan_nhan — gọi dan_nhan hai lần cho ra [VIP]\n[Uu tien], computed field co_ghi_chu chuyển False→True. Quan trọng: cột của mixin nằm trong bảng của chính model thật (quan_the_thanh_vien), không phải ở đâu khác.
Câu cuối là điểm cốt lõi: mixin không có bảng, nhưng khi trộn vào một model có bảng, các field của nó thành cột của bảng đó. Nhiều model cùng trộn mixin thì mỗi model có cột riêng trong bảng riêng — code chung, dữ liệu riêng.
AbstractModel vs Model vs TransientModel
Ba loại model trong Odoo, phân biệt bằng chuyện bảng:
models.Model— model thường, có bảng, lưu dữ liệu nghiệp vụ lâu dài.models.TransientModel— có bảng nhưng bản ghi tự dọn (xem bài wizard).models.AbstractModel— không có bảng, chỉ để cho đi code qua kế thừa.
Thực ra Model và TransientModel đều kế thừa từ AbstractModel bên trong Odoo — abstract là gốc chung, còn hai cái kia thêm phần "có bảng".
Khi nào nên viết mixin
- Cùng một tập field/logic lặp ở nhiều model: trạng thái duyệt, dấu vết ghi chú, tính toán chung. Gói thành mixin,
_inheritvào từng model. - Muốn dùng tính năng có sẵn của Odoo:
_inherit = ['mail.thread']cho model của bạn khả năng theo dõi thay đổi và có khung trao đổi;mail.activity.mixincho lịch hoạt động. Đây chính là mixin của Odoo core. - Không nên khi logic chỉ dùng cho đúng một model — lúc đó viết thẳng vào model gọn hơn.
Một lưu ý về _inherit: khi _inherit kèm _name mới (như ví dụ trên), bạn đang tạo model mới và trộn mixin vào. Khi _inherit không kèm _name, bạn đang mở rộng model đã có — đó là chuyện của một bài khác.
Ba ý mang về
- AbstractModel là model không sinh bảng (
_abstract=True, không có bảng trong DB) — dùng để gói field, computed field và method dùng lại. Đã kiểm chứng:quan_mixin_dau_vetkhông tồn tại tronginformation_schema.tables. - Trộn mixin bằng một dòng
_inherit = ['ten.mixin']: model thật nhận đủ field + method của mixin, và field của mixin thành cột trong bảng của chính model đó (đã thấy cộtghi_chu_noi_botrong bảngquan_the_thanh_vien). - Ba loại model phân biệt bằng bảng:
Model(có bảng, lưu lâu),TransientModel(có bảng, tự dọn),AbstractModel(không bảng, chỉ cho code). Mixin nổi tiếng của Odoo:mail.thread,mail.activity.mixin.
Ngoài kế thừa để trộn code, Odoo còn một kiểu kế thừa nữa gắn hẳn model này vào model khác: Phần sau nói về _inherits (có chữ "s") — kế thừa ủy quyền (delegation), cách một model "mượn" toàn bộ field của model khác qua một liên kết.