Đọc dữ liệu trong Odoo có ba phương thức hay dùng, và người mới thường chỉ biết search rồi dùng nó cho mọi thứ. Nhưng dùng đúng phương thức cho đúng nhu cầu vừa gọn code vừa nhanh hẳn. Nối tiếp create và write, bài này so sánh search, search_count, search_read.
Ba phương thức, ba kiểu trả về
Điểm khác biệt cốt lõi: chúng trả về những thứ khác nhau, và thứ trả về quyết định chi phí.

Hình 1: search trả recordset (object ORM đầy đủ — thao tác tiếp được). search_count trả số nguyên (chỉ đếm). search_read trả list dict (chỉ những trường bạn xin). Chọn phương thức = chọn đúng lượng công việc cần làm.
Đo thật: search_count vs len(search)
Bẫy phổ biến nhất: cần đếm mà viết len(search([...])). Điều đó bắt Odoo nạp toàn bộ bản ghi thành recordset rồi mới đếm. Đây là số đo thật trên 3030 bản ghi res.partner:

Hình 2: Số đo thật. search_count([]) chỉ chạy một câu SELECT count(*) — 0.0006 giây. Còn len(search([])) phải nạp cả 3030 recordset rồi đếm — 0.0010 giây, chậm 1.6 lần và tốn bộ nhớ dựng object. Trên bảng vài trăm nghìn dòng, khác biệt này là giây với chục giây, chưa kể RAM.
Khi nào dùng cái nào
search — khi cần làm gì đó với bản ghi
orders = env['sale.order'].search([('state', '=', 'draft')])
orders.action_confirm() # gọi method, write, đọc quan hệ...
Chỉ dùng search khi bạn thực sự cần recordset để thao tác tiếp. Nó nạp object ORM đầy đủ (đắt nhất trong ba cái).
search_count — khi chỉ cần một con số
if env['sale.order'].search_count([('state', '=', 'draft')]) > 100:
self.canh_bao_ton_dong()
Badge đếm, điều kiện "có quá N bản ghi không", thống kê nhanh — luôn dùng search_count, đừng bao giờ len(search(...)).
search_read — khi chỉ cần đọc vài trường
data = env['res.partner'].search_read(
[('is_company', '=', True)],
['name', 'email', 'city'], # chỉ lấy 3 trường
limit=20,
)
# data = [{'id':.., 'name':.., 'email':.., 'city':..}, ...]
search_read gộp "tìm + đọc" thành một lời gọi và trả thẳng list dict — không dựng object ORM. Cực hợp cho báo cáo, API/RPC, xuất JSON: bạn cần dữ liệu thô để trả về client, không cần method của model. Đây cũng chính là phương thức mà giao diện web Odoo gọi để nạp danh sách.
Vài tinh chỉnh chung
Cả ba đều nhận thêm tham số điều khiển kết quả:
P.search(domain, limit=10, offset=20, order='name desc')
limit: số bản ghi tối đa (phân trang).offset: bỏ qua N bản ghi đầu (trang thứ mấy).order: sắp xếp ('create_date desc'); mặc định theo_ordercủa model.
search_count bỏ qua limit/offset/order (đếm thì không cần), còn search và search_read dùng đủ.
Nhớ ba ý
searchtrả recordset (thao tác tiếp),search_counttrả số (chỉ đếm),search_readtrả list dict (chỉ đọc trường) — chọn đúng cái để làm đúng lượng việc.- Đừng
len(search([...]))để đếm — đo thậtsearch_countnhanh 1.6 lần trên 3030 bản ghi và không tốn RAM nạp object; chênh lệch giãn mạnh khi bảng lớn. search_readgộp tìm + đọc thành một lời gọi, trả dict thô — lý tưởng cho báo cáo, API, JSON; dùnglimit/offset/orderđể phân trang và sắp xếp.
Ba phương thức đều nhận domain làm điều kiện lọc. Phần sau đào sâu cú pháp domain — dạng [(field, op, value)], các toán tử, và cách viết điều kiện lọc cho đúng.