Đọ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:

Cách dùng create trong Odoo 19 tạo một bản ghi và tạo hàng loạt trong một lệnh: tạo một truyền một dict env res.partner create với name Cửa hàng A, city Huế, is_company True trả về recordset một phần tử res.partner 37; tạo nhiều truyền một list dict từ Odoo 12 trở lên, env res.partner create với list ba dict gồm Chi nhánh 1 Hà Nội, Chi nhánh 2 Đà Nẵng, Chi nhánh 3 Cần Thơ, trả về recordset nhiều res.partner 38 39 40; phần đừng làm thế này khi tạo nhiều là vòng for data in danh_sach rồi P.create data mỗi vòng một lần create riêng chậm và nhiều lượt xử lý, thay vào đó P.create danh_sach một lệnh Odoo gộp tối ưu

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:

Đo hiệu năng thật create lẻ so với batch trên database blog19: tạo 200 bản ghi res.partner bằng hai cách và đo thời gian; cách một dùng vòng for i in range 200 gọi P.create với name Le i mỗi vòng, kết quả 200 create lẻ mất 0.334 giây; cách hai gọi P.create một lần với list comprehension name Batch i for i in range 200, kết quả 1 create batch 200 mất 0.110 giây; khung nhấn mạnh batch nhanh hơn 3.0 lần; create trả về recordset của các bản ghi vừa tạo, P.create một dict Demo trả res.partner 37, P.create list ba dict trả res.partner 38 39 40; ghi chú càng nhiều bản ghi khoảng cách càng lớn có list dữ liệu thì luôn create một lần

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:

  1. 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.
  2. Tính trường computed một lần cho cả lô: các hàm @api.depends chạy trên recordset nhiều phần tử — một lượt thay vì N lượt.
  3. 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 ý

  1. 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.
  2. 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.
  3. 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.