Trường quan hệ nhiều bản ghi — One2many (dòng đơn hàng) và Many2many (thẻ, ưu đãi) — không ghi như trường thường. Bạn không thể order.order_line = [1, 2, 3]. Odoo dùng một bộ lệnh đặc biệt để nói rõ: thêm dòng nào, sửa dòng nào, gỡ dòng nào. Đó là Command (0..6). Mở màn chương "trường quan hệ", đây là kỹ năng bạn dùng mỗi khi thao tác dòng con bằng code.
Bảy lệnh Command
Trường O2m/M2m nhận một list các Command, mỗi Command là một thao tác:

Hình 1: Bảy Command. Mã 0 create (tạo dòng con mới), 1 update (sửa dòng con), 2 delete (xoá hẳn — cho O2m), 3 unlink (gỡ liên kết, giữ bản ghi), 4 link (thêm liên kết tới bản ghi có sẵn — cho M2m), 5 clear (gỡ hết), 6 set (thay toàn bộ bằng danh sách ids). Odoo 19 có API tên rõ ràng: Command.create(), Command.link()... thay cho tuple số khó nhớ (0,0,{}).
Chạy thật — cả bảy thao tác
Model quan.the.thanh.vien có lich_su_ids (One2many các dòng điểm) và uu_dai_ids (Many2many ưu đãi). Tôi chạy các Command thật trên db blog19:

Hình 2: Output thật. Tạo thẻ kèm 2 dòng lịch sử (Command.create) và 1 ưu đãi (Command.link) cùng lúc. Rồi Command.link thêm ưu đãi thứ 2 → có 2. Command.unlink gỡ 1 dòng lịch sử → còn 1. Command.set([ud2]) thay toàn bộ M2m thành đúng 1 ưu đãi. Command.update sửa ghi chú dòng con thành "ĐÃ SỬA". Mọi thao tác đều đúng như tên lệnh.
Import Command
Odoo 19 khuyến khích dùng API tên thay cho tuple số:
from odoo.fields import Command
# Cách MỚI (rõ ràng):
'order_line': [Command.create({'product_id': 1, 'product_uom_qty': 2})]
# Cách cũ (tuple số — vẫn chạy nhưng khó đọc):
'order_line': [(0, 0, {'product_id': 1, 'product_uom_qty': 2})]
Ánh xạ: Command.create = (0,0,{}), update = (1,id,{}), delete = (2,id), unlink = (3,id), link = (4,id), clear = (5,), set = (6,0,[ids]).
Phân biệt hai cặp dễ nhầm
delete (2) vs unlink (3)
Command.delete(id): xoá hẳn bản ghi con khỏi CSDL. Dùng cho One2many (dòng con thuộc về cha, xoá là đúng).Command.unlink(id): chỉ gỡ liên kết, bản ghi vẫn tồn tại. Dùng cho Many2many (ưu đãi vẫn còn, chỉ không áp cho thẻ này nữa).
Dùng delete trên M2m là xoá nhầm bản ghi dùng chung — cẩn thận!
link (4) vs create (0)
Command.link(id): gắn tới bản ghi đã có (M2m — chọn ưu đãi có sẵn).Command.create({...}): tạo bản ghi mới (O2m — thêm dòng lịch sử mới).
Dùng ở đâu?
- create/write model cha với dòng con cùng lúc (như Hình 2).
- Nút hành động thêm/bớt dòng bằng code.
- Onchange điền dòng con tự động.
- Import dữ liệu có quan hệ lồng nhau.
Trên giao diện, mỗi lần bạn thêm/xoá dòng trong bảng con của form rồi Lưu, Odoo cũng sinh đúng các Command này gửi xuống.
Nhớ ba ý
- Trường One2many/Many2many nhận list Command, không gán trực tiếp; Odoo 19 dùng
Command.create/update/delete/unlink/link/clear/set(thay tuple số 0..6). - Đo thật:
Command.createthêm dòng O2m,Command.linkgắn M2m,Command.set([ids])thay toàn bộ,Command.unlink/updategỡ/sửa dòng con. delete(2) xoá hẳn (cho O2m) vsunlink(3) chỉ gỡ liên kết (cho M2m) — nhầm là xoá nhầm bản ghi dùng chung;link(4) gắn bản ghi có sẵn vscreate(0) tạo mới.
Xong thao tác trên quan hệ nhiều bản ghi. Có một loại trường đặc biệt khác hay dùng: danh sách lựa chọn. Phần sau đi vào trường Selection — khai lựa chọn tĩnh và cách sinh lựa chọn động bằng hàm.