Mở danh sách đơn hàng, đơn mới nhất luôn ở trên. Mở danh bạ, tên xếp A→Z. Không ai bấm nút "sắp xếp" — thứ tự đó là mặc định, khai bằng một thuộc tính duy nhất: _order. Khép lại chương "trường thông minh & thuộc tính model", bài này bàn cách đặt và những cái bẫy của nó.

_order = ORDER BY mặc định

_order là chuỗi khai trên model, được Odoo dịch thành mệnh đề ORDER BY của SQL cho mọi truy vấn không tự khai order:

_order thứ tự sắp xếp mặc định của model trong Odoo 19: khai _order trên model, class TheThanhVien có _order bằng diem desc name asc nghĩa điểm cao lên đầu rồi tên A đến Z; mọi search list rỗng không truyền order sẽ dùng thứ tự này thành ORDER BY của SQL; vài ví dụ core sale.order dùng date_order desc id desc đơn mới nhất lên đầu, res.partner dùng complete_name asc id desc, mặc định là id không khai thì theo id tăng dần; override tại chỗ khi cần Model.search domain order bằng name asc bỏ qua _order cho lần này; lưu ý hiệu năng sắp theo trường không có index thì chậm trên bảng lớn, chỉ sắp được theo trường có cột SQL store True computed không store thì không, sắp theo Many2one thì sắp theo trường định danh của bản ghi liên kết qua JOIN

Hình 1: _order = 'diem desc, name asc' — sắp theo nhiều tiêu chí, mỗi cái kèm asc/desc, ngăn bằng dấu phẩy. Đọc: "điểm giảm dần; cùng điểm thì tên tăng dần". Không khai _order thì mặc định là 'id' (theo id tăng dần). Muốn khác cho một truy vấn thì truyền order=... vào search.

Chạy thật — thứ tự đúng như khai

Tôi thêm _order = 'diem desc, name asc' vào model quan.the.thanh.vien, tạo 4 thẻ, rồi search([]) không truyền order. Output thật trên db blog19:

Output _order chạy thật trên module quan_ca_phe database blog19: đã khai _order bằng diem desc name asc, tạo 4 thẻ ORD-B điểm 50, ORD-A điểm 100, ORD-D điểm 100, ORD-C điểm 10; search list với name like ORD không truyền order dùng _order mặc định trả về ORD-A điểm 100 rồi ORD-D điểm 100 vì điểm 100 lên đầu và cùng điểm thì tên A đến Z nên A trước D, tiếp ORD-B điểm 50, cuối ORD-C điểm 10 điểm thấp nhất xuống cuối; override order tại chỗ bỏ qua _order, search với order name asc trả về ORD-A ORD-B ORD-C ORD-D; _order là ORDER BY mặc định áp cho mọi truy vấn không tự khai order

Hình 2: Output thật. search([]) trả về đúng thứ tự _order: ORD-A và ORD-D (điểm 100) lên đầu, cùng điểm thì tên A→Z nên A trước D; rồi ORD-B (50), cuối là ORD-C (10). Truyền order='name asc' thì bỏ qua _order, trả về A,B,C,D. _order chỉ là mặc định — luôn override được tại chỗ.

Vài ví dụ core

  • sale.order: 'date_order desc, id desc' — đơn mới nhất lên đầu (cái bạn thấy hằng ngày).
  • res.partner: 'complete_name asc, id desc' — tên A→Z.
  • Không khai: 'id' — theo thứ tự tạo (id tăng dần).

id desc ở cuối thường là tiêu chí phá hòa: cùng ngày/tên thì bản ghi mới hơn (id lớn hơn) lên trước, đảm bảo thứ tự ổn định.

Ba cái bẫy hiệu năng

1. Sắp theo trường không index → chậm

Trên bảng lớn, ORDER BY một trường không có index buộc PostgreSQL sắp toàn bộ (sort tốn kém). Nếu _order theo trường hay dùng, cân nhắc thêm index=True cho trường đó.

2. Chỉ sắp được theo trường có cột SQL

_order phải theo trường có cột thật (thường store=True). Sắp theo computed không store sẽ lỗi — không có cột để ORDER BY. Đây là một lý do nữa để store=True khi cần sắp xếp.

3. Sắp theo Many2one = JOIN

_order = 'partner_id' không sắp theo id, mà theo trường định danh của partner (display_name/complete_name) — Odoo sinh JOIN. Đúng ý người dùng nhưng nặng hơn; nhiều tầng thì cân nhắc.

Override tại chỗ

_order chỉ là mặc định. Mọi lúc bạn có thể truyền order để đổi:

# Lấy 5 thẻ điểm cao nhất, bất kể _order
top = env['quan.the.thanh.vien'].search([], order='diem desc', limit=5)

Giao diện cũng cho người dùng bấm tiêu đề cột để đổi thứ tự — lúc đó Odoo truyền order tương ứng, _order bị bỏ qua cho lần xem đó.

Nhớ ba ý

  1. _order là ORDER BY mặc định của model ('diem desc, name asc'), áp cho mọi truy vấn không tự khai order; đo thật: điểm giảm dần, cùng điểm thì tên A→Z.
  2. Thêm id desc ở cuối làm tiêu chí phá hòa cho thứ tự ổn định; không khai _order thì mặc định 'id'.
  3. Bẫy: sắp theo trường không index → chậm; theo computed không store → lỗi; theo Many2one → JOIN. Luôn override được bằng order=... trong search.

Xong nhóm thuộc tính model. Chương tiếp đào sâu trường quan hệ — thao tác trên One2many/Many2many. Phần sau đi vào Command (0..6) — bộ lệnh đặc biệt để thêm/bớt/sửa bản ghi con trong trường quan hệ nhiều-nhiều và một-nhiều.