Đọc và lấy bản ghi đã thạo (recordset, ensure_one), giờ tới lúc tạo dữ liệu. create() nhìn đơn giản, nhưng có một chi tiết ảnh hưởng lớn tới hiệu năng: nó tạo một hay nhiều bản ghi tuỳ bạn truyền dict hay list. Dùng đúng, code nhanh gấp mấy lần — và tôi sẽ đo thật để bạn thấy.
Một dict → một bản ghi; một list → nhiều bản ghi
create() nhận dict thì tạo một bản ghi; nhận list các dict thì tạo nhiều bản ghi trong một lệnh (từ Odoo 12 trở đi). Cả hai đều trả về recordset của bản ghi vừa tạo:

Hình 1: create({...}) (dict) → recordset một phần tử res.partner(37,). create([{...},{...},{...}]) (list) → recordset nhiều res.partner(38, 39, 40). Điểm mấu chốt ở dưới cùng: khi có sẵn danh sách dữ liệu, đừng gọi create trong vòng for — hãy truyền cả list vào một lần create.
Vì sao create theo lô nhanh hơn? Đo thật
Không chỉ nói suông — đây là số đo thật khi tạo 200 bản ghi res.partner bằng hai cách trên db blog19:

Hình 2: Số đo thật. 200 lần create lẻ trong vòng for mất 0.334 giây; một lệnh create nhận list 200 dict chỉ 0.110 giây — nhanh gấp 3 lần. Lý do: create theo lô cho Odoo gộp phần lớn công việc — chèn nhiều dòng bằng ít câu SQL hơn, và chỉ tính lại các trường computed một lần cho cả lô thay vì lặp lại 200 lần.
Bên trong: create theo lô làm gì
Khi bạn truyền một list, Odoo:
- Gộp INSERT: chèn nhiều dòng bằng ít câu SQL hơn nhiều so với 200 câu riêng.
- Tính trường computed một lần cho cả lô: các hàm
@api.dependschạy trên recordset nhiều phần tử — một lượt thay vì N lượt. - Chạy ràng buộc/onchange gộp: giảm số lần lặp qua các lớp kiểm tra.
Càng nhiều bản ghi, khoảng cách càng giãn ra. Với vài nghìn dòng (nhập dữ liệu, đồng bộ), khác biệt là giây với phút.
Vài lưu ý khi create
- Trường quan hệ Many2one: truyền id, ví dụ
'partner_id': 5. Truyền recordset cũng được ('partner_id': partner.id). - Trường One2many/Many2many: dùng lệnh đặc biệt (sẽ có bài riêng), ví dụ tạo dòng con cùng lúc:
env['sale.order'].create({ 'partner_id': 5, 'order_line': [(0, 0, {'product_id': 1, 'product_uom_qty': 2})], # (0,0,{}) = tạo mới }) - Giá trị mặc định: trường không truyền sẽ lấy default của model (từ
default=hoặc_default_get). - create trả về recordset, không phải id — muốn id thì
.id, muốn cả tập id thì.ids.
Khi nào vẫn phải create trong vòng lặp?
Nếu mỗi bản ghi phụ thuộc kết quả của bản ghi trước (ví dụ phải đọc id vừa tạo để tính dữ liệu tiếp theo), thì đành lặp. Nhưng phần lớn trường hợp nhập liệu, dữ liệu là độc lập — gom thành list rồi create một lần.
# Có sẵn danh sách dữ liệu độc lập → gom lại, create MỘT lần
vals_list = [{'name': ten, 'city': tp} for ten, tp in du_lieu]
env['res.partner'].create(vals_list)
Nhớ ba ý
create(dict)tạo một bản ghi;create([dict, ...])tạo nhiều trong một lệnh — cả hai trả recordset của bản ghi mới.- Create theo lô nhanh hơn hẳn create trong vòng
for— đo thật gấp 3 lần cho 200 bản ghi, vì Odoo gộp SQL và tính computed một lượt. - Có sẵn list dữ liệu độc lập thì luôn create một lần; chỉ lặp khi bản ghi sau phụ thuộc bản ghi trước.
Tạo xong rồi tới sửa. Phần sau đi vào write() — cơ chế cập nhật bản ghi, cách nó ghi hàng loạt bằng một câu SQL, và những gì xảy ra ngầm khi bạn gán một trường.