Người dùng muốn xem thẻ gom theo hạng, trong mỗi hạng lại chia theo trạng thái, và mỗi nhóm tự cộng tổng điểm. Nghe như một báo cáo phải code, nhưng Odoo làm được chỉ bằng khai báo. Có ba tầng điều khiển thứ tự và nhóm: _order của model, default_order của list, và group_by của search view. Hiểu chúng phối hợp thế nào là bạn kiểm soát trọn cách dữ liệu được sắp và gom. Bài này gom thẻ hai cấp với subtotal thật.
Ba tầng điều khiển
# 1) _order trên MODEL: thứ tự MẶC ĐỊNH của mọi search trên model này
class TheThanhVien(models.Model):
_order = 'diem desc, name asc' # điểm cao lên đầu, rồi tên A→Z
<!-- 2) default_order trên LIST: ghi đè _order cho riêng list này -->
<list default_order="diem desc"> ... </list>
<!-- 3) Nhóm: khai filter group_by trong SEARCH view -->
<group name="group_by">
<filter name="gb_hang" string="Hạng thẻ" context="{'group_by':'hang_the'}"/>
<filter name="gb_tt" string="Trạng thái" context="{'group_by':'trang_thai'}"/>
</group>

Hình 1: Ba tầng. _order (model) là thứ tự mặc định cho mọi truy vấn trên model — điểm giảm dần, rồi tên tăng dần. default_order (list) ghi đè _order riêng cho list đó. group_by (search) cho người dùng gom; chọn hai filter group liên tiếp → nhóm nhiều cấp. Dòng _read_group là API tính subtotal ở tầng SQL.
Xem thật: nhóm hai cấp với subtotal
Chọn nhóm "Hạng thẻ" rồi "Trạng thái", list gom hai cấp và tự cộng tổng:

Hình 2: Nhóm hai cấp chạy thật. Chip "Hạng thẻ > Trạng thái" cho biết đang gom hai cấp. Nhóm cấp 1 Bạc (3): 235 bung ra thành cấp 2 theo trạng thái: Đang dùng (1): 150, Hết hạn (1): 85, Đã khoá (1): 0. Nhóm Vàng (1): 150 (thu gọn). Chân bảng tổng 385. Mỗi nhóm tự đếm số bản ghi và cộng tổng cột số có sum — không viết dòng tính nào.
Con số 235 (=150+85+0) và tổng 385 (=235+150) do Odoo tự tính bằng _read_group ở tầng SQL — nhanh kể cả trên hàng nghìn bản ghi vì database gộp hộ.
Thứ tự sắp xếp phối hợp thế nào
_order(model) là nền: mọisearchkhông truyềnorderđều theo nó. Đặt_ordercho ý nghĩa nghiệp vụ mặc định (mới nhất trước, ưu tiên cao trước).default_order(list) ghi đè_orderchỉ cho list đó — hữu ích khi một màn hình cần thứ tự khác mặc định.- Người dùng bấm tiêu đề cột để sort tạm — ghi đè cả hai, chỉ trong phiên xem.
- Trong mỗi nhóm, các bản ghi vẫn sắp theo
_order/default_order.
Ba tầng theo thứ tự ưu tiên: cột người dùng bấm > default_order > _order.
Cạm bẫy: field không store không sort/group được
Đây là giới hạn quan trọng. Sắp xếp và nhóm chạy ở tầng SQL (database). Một field computed không store=True chỉ tồn tại trong bộ nhớ Python, không có cột trong bảng — nên database không sort/group theo nó được. Nếu bạn cần sort/group theo một computed field, phải khai store=True để nó có cột thật.
Vài lưu ý Odoo 19
_orderdùng tên cột SQL — field quan hệ sort theoidtrừ khi field đích có_orderphù hợp; sort theo field của bản ghi liên kết cần cú pháppartner_id.name(giới hạn).- Nhóm nhiều cấp: chọn các group_by theo thứ tự bạn muốn lồng; bỏ chọn để tháo cấp.
- Subtotal chỉ hiện cho cột có
sum/avgtrong list (bài list view); nhóm không tự cộng cột không khai. _read_group(Odoo 19; trước làread_group) là API đọc dữ liệu đã gom — dùng khi cần số liệu nhóm trong code.
Ba ý mang về
- Ba tầng thứ tự:
_order(model, mặc định toàn hệ thống) <default_order(list, ghi đè cho list đó) < cột người dùng bấm (tạm thời). Trong mỗi nhóm vẫn sắp theo order. - Nhóm nhiều cấp qua
group_bycủa search: chọn 2 filter group liên tiếp → lồng (Hạng thẻ > Trạng thái); mỗi nhóm tự đếm và cộng subtotal cột cósum. Đã chứng minh: Bạc 235 (Đang dùng 150 / Hết hạn 85 / Đã khoá 0), Vàng 150, tổng 385. - Sắp/nhóm chạy ở SQL → field computed phải
store=Truemới sort/group được; dùng_read_groupđể lấy số liệu nhóm trong code.
Nói tới list, còn một chế độ khiến bảng thành nơi nhập liệu chứ không chỉ xem: Phần sau mổ xẻ editable list — cho sửa và thêm dòng ngay trên bảng (editable="top"/"bottom"), tiện cho dòng chi tiết mà không cần mở form.