Nhiều thao tác cần người dùng nhập vài thông số rồi bấm chạy: cộng điểm hàng loạt, đổi trạng thái kèm lý do, xuất một báo cáo có tham số. Cái hộp thoại đó cần một model để chứa những gì người dùng gõ vào. Nhưng lưu vĩnh viễn thì phí — nhập xong là bỏ. Odoo giải quyết bằng TransientModel: một model mà bản ghi của nó là tạm, tự dọn định kỳ. Đó chính là wizard. Bài này mổ xẻ luồng cơ bản của một wizard cộng điểm.
TransientModel: model của dữ liệu tạm
Một wizard chỉ là một class kế thừa models.TransientModel thay vì models.Model. Field khai y như model thường, nhưng bản ghi được lưu vào bảng riêng và bị cơ chế vacuum dọn sau một thời gian:

Hình 1: Wizard quan.them.diem.wizard là TransientModel. Field khai như thường. default_get điền sẵn khi mở hộp thoại — ở đây nạp the_ids từ active_ids trong context (các thẻ được chọn). action_cong_diem là việc nút "Lưu" gọi: cộng điểm cho từng thẻ, rồi trả act_window_close để đóng dialog.
Ba mảnh của luồng wizard:
- TransientModel giữ dữ liệu tạm — không đụng bảng của model thật.
default_get+active_ids— khi mở wizard từ một danh sách/bản ghi, context mang theoactive_ids;default_getđọc nó để nạp sẵn các bản ghi liên quan.- Method của nút — làm việc thật (đổi dữ liệu model chính), rồi trả một action:
act_window_closeđể đóng, hoặc mộtact_windowkhác để đi tiếp.
Wizard bật lên và điền sẵn
Wizard mở dạng dialog (nhờ action target="new" ở bài window action). Nó tự điền thẻ đang xem vào ô "Thẻ áp dụng":

Hình 2: Wizard hiện dạng dialog. Ô "Số điểm cộng thêm" mặc định 10; "Thẻ áp dụng" đã có sẵn VIP-0001 — đó là default_get đọc active_ids và nạp vào. Người dùng chỉnh số, thêm lý do, bấm "Lưu" (gọi action_cong_diem), dialog đóng và điểm được cộng. "Huỷ bỏ" chỉ đóng, không lưu gì — vì đằng nào bản ghi wizard cũng là tạm.
Vòng đời một wizard — nhìn tận nơi
Để thấy rõ "bản ghi tạm", tôi chạy trực tiếp qua odoo shell:

Hình 3: _transient là True — xác nhận đây là bản ghi tạm. Tạo wizard với active_ids của VIP-0004, default_get nạp đúng thẻ đó vào the_ids. Gọi action_cong_diem: điểm 0 → 10, method trả act_window_close. Bản ghi wizard này rồi sẽ bị vacuum dọn — không để lại rác.
Vì sao dùng TransientModel, không phải Model thường
- Không rác trong CSDL. Mỗi lần mở wizard tạo một bản ghi; nếu là Model thường, chúng tích lại mãi. TransientModel được vacuum dọn tự động.
- Đúng ngữ nghĩa "tạm". Dữ liệu wizard là đầu vào cho một thao tác, không phải thực thể nghiệp vụ cần lưu. Model "tạm" phản ánh đúng điều đó.
- Vẫn đủ sức mạnh của ORM. Wizard có field, quan hệ, method, view như model thường — chỉ khác vòng đời.
the.diem += ...trong method wizard chạy bình thường (đây là method Python thật, không phải sandbox như server action code).
Ba ý mang về
- Wizard =
TransientModel: model có bản ghi tạm, lưu ở bảng riêng và bị vacuum dọn định kỳ — hợp cho hộp thoại nhập liệu, không để rác trong CSDL. default_get+ contextactive_idsnạp sẵn bản ghi được chọn khi mở wizard; mở dạng dialog bằng actiontarget="new".- Method của nút làm việc thật rồi trả action:
act_window_closeđể đóng, hoặc mộtact_windowkhác để đi bước tiếp — và trong method wizard, đổi dữ liệu bằng gán thuộc tính bình thường (không phải sandbox).
Wizard một bước đã xong. Nhưng nhiều tác vụ cần nhiều bước — chọn, xác nhận, xem kết quả. Bài sau: Phần sau về wizard nhiều bước — cách một wizard dẫn người dùng qua từng màn hình bằng cách method trả về chính nó (hoặc một wizard khác) với dữ liệu mang theo.