Bạn muốn kiểm tra nhanh: "có bao nhiêu partner là công ty?", "trường name có bắt buộc không?", "tạo thử một bản ghi xem nó ra sao?". Viết hẳn một module để thử mấy câu đó thì quá phí. Odoo có một công cụ gọn hơn nhiều: odoo shell — một dấu nhắc Python đã nạp sẵn toàn bộ ORM và gắn thẳng vào cơ sở dữ liệu.

Sau khi đã biết bật chế độ dev, đây là công cụ thứ hai bạn sẽ dùng hằng ngày.

Mở shell

Lệnh giống hệt lệnh chạy server, chỉ thêm chữ shell:

Khối mã cách mở odoo shell trong Odoo 19: docker exec vào odoo19 chạy odoo shell với database blog19 và no-http; trong shell có sẵn env và self bằng OdooBot; ví dụ env.uid trả 1, lấy model res.partner qua env, search_count đếm 30, search với is_company bằng True giới hạn 3 trả res.partner 1 6 10; tạo bản ghi bằng create rồi gọi env.cr.commit để chốt xuống cơ sở dữ liệu, cuối cùng unlink và commit để dọn

Hình 1: Mở odoo shell và vài thao tác ORM. Chú ý: shell nạp sẵn env (môi trường ORM) và self (mặc định là OdooBot, uid 1). Không cần import gì cả — cứ env['tên.model'] là có model để làm việc.

Ba biến có sẵn: env, self, model

  • env — môi trường ORM: env.uid (người đang chạy), env.user, env.cr (con trỏ CSDL), env.company. Lấy model bằng env['res.partner'].
  • self — một recordset khởi tạo sẵn, mặc định là res.users(1,) tức OdooBot.
  • Truy vấn qua model: search, search_count, read, create, write, unlink.

Đây là output thật khi tôi chạy trên CSDL blog19 của loạt bài này (dữ liệu mẫu quán cà phê):

Ảnh chụp output thật từ odoo shell trên cơ sở dữ liệu blog19: self là res.users 1, env.uid 1 user OdooBot; tổng partner 30; ba công ty là res.partner id 1 6 10 gồm hai Công ty TNHH Cà Phê Việt ở Thành phố Hồ Chí Minh và một Global Tech Corp ở New York; field name kiểu char required False; read trả về id 1 name Công ty TNHH Cà Phê Việt email lienhe caphe-viet vn; product template đếm 36; phần ghi có commit tạo bản ghi id 36 tên Khách thử ORM shell rồi tìm lại thấy 36 và xoá xong còn 0

Hình 2: Output thật. search_count([]) cho 30 partner; search([('is_company','=',True)], limit=3) trả về recordset res.partner(1, 6, 10). P._fields['name'].type cho biết trường name kiểu char, required=False. Phần dưới là một vòng create → commit → tìm lại → unlink → commit chạy thật rồi dọn sạch (còn 0).

search nhận một domain — danh sách các bộ ba (trường, toán tử, giá trị):

# Tất cả partner là công ty
env['res.partner'].search([('is_company', '=', True)])

# Partner ở TP.HCM VÀ có email (mặc định các điều kiện nối bằng AND)
env['res.partner'].search([
    ('city', 'ilike', 'Hồ Chí Minh'),
    ('email', '!=', False),
])

# Toán tử logic tường minh: '|' là HOẶC cho 2 điều kiện kế tiếp
env['res.partner'].search(['|', ('city', '=', 'Hà Nội'), ('city', '=', 'Đà Nẵng')])

Vài toán tử hay dùng: =, !=, in, not in, >, <, like (phân biệt hoa thường), ilike (không phân biệt), child_of. Domain rỗng [] nghĩa là lấy tất cả.

Ghi dữ liệu: đừng quên env.cr.commit()

Đây là cái bẫy khiến người mới bối rối nhất. Trong shell, mọi thao tác create/write/unlink chỉ nằm trong giao dịch (transaction) hiện tại. Nếu bạn thoát shell mà không commit, giao dịch bị rollback — mọi thay đổi bốc hơi:

p = env['res.partner'].create({'name': 'Khách thử', 'city': 'Đà Nẵng'})
env.cr.commit()   # ← BẮT BUỘC: chốt xuống CSDL. Thiếu dòng này là mất trắng.

Khác với khi code trong module (Odoo tự commit ở cuối request), shell để bạn tự quyết định lúc nào chốt. Điều này có mặt lợi: thử một thao tác nguy hiểm mà chưa commit thì cứ Ctrl+D thoát ra là như chưa từng xảy ra.

Vài mẹo thực dụng

  • Chạy với user thật, không phải OdooBot: env = env(user=2) rồi thao tác — để kiểm tra quyền đúng như người dùng đó thấy.
  • Đổi công ty ngữ cảnh: env['res.partner'].with_company(cid).search(...).
  • Chạy script không cần gõ tay: nối bằng heredoc — docker exec -i odoo19 odoo shell -d blog19 <<'PY' ... PY. Cả loạt bài này đo dữ liệu thật bằng đúng cách đó.
  • Thử nghiệm an toàn: cứ thử thoải mái, chỉ cần không commit thì không có gì xuống CSDL.

Cảnh báo

Shell nối thẳng vào CSDL production là con dao hai lưỡi: một câu search([]).unlink() gõ nhầm là xoá sạch bảng. Nguyên tắc: thử trên CSDL sao chép trước, và chỉ commit() khi chắc chắn.

Nhớ ba ý

  1. odoo shell là REPL Python nạp sẵn env, self (OdooBot) và toàn bộ ORM — nghịch dữ liệu mà khỏi viết module.
  2. search chạy bằng domain (danh sách bộ ba điều kiện); [] là lấy tất cả, ilike không phân biệt hoa thường.
  3. Ghi dữ liệu phải env.cr.commit() mới xuống CSDL — mặt trái là chỗ an toàn để thử: không commit thì không có gì thay đổi.

Chạy được ORM rồi, bạn sẽ cần nhìn Odoo "nói" gì khi có chuyện. Phần sau học cách đọc log Odoo và chỉnh cấp log theo từng module để soi đúng thứ mình cần.