Một bảng danh sách dài mà mọi dòng đen sì như nhau thì mắt phải căng ra tìm cái quan trọng. Odoo có một cách để bảng tự làm nổi bật thứ cần chú ý: decoration-* — tô màu và đổi kiểu chữ từng dòng theo một biểu thức điều kiện. Ta đã gặp thoáng qua ở bài list view; bài này đi sâu vào cả bảng màu, cách ghép nhiều decoration, và cạm bẫy hay quên. Dựng thật một list với thẻ khoá đỏ, thẻ hết hạn cam, thẻ VIP xanh đậm.
Cú pháp: decoration-MÀU="biểu thức"
Mỗi thuộc tính decoration-<màu> nhận một biểu thức Python; dòng nào làm biểu thức đúng thì được tô màu/kiểu đó:
<list string="Thẻ thành viên" default_order="diem desc"
decoration-success="diem >= 100" <!-- XANH lá -->
decoration-bf="diem >= 150" <!-- IN ĐẬM -->
decoration-warning="trang_thai == 'het_han'" <!-- CAM -->
decoration-danger="trang_thai == 'khoa'" <!-- ĐỎ -->
decoration-muted="diem == 0"> <!-- XÁM mờ -->
<field name="name"/>
<field name="diem" sum="Tổng điểm"/>
<field name="trang_thai"/> <!-- field dùng trong biểu thức PHẢI có trong list -->
</list>

Hình 1: Năm decoration cùng khai trên một list. Mỗi cái là một cặp màu/kiểu + biểu thức. Biểu thức đọc field của dòng đang xét. Chú ý dòng cuối: trang_thai phải là một field trong list thì biểu thức mới đọc được nó — đây là cạm bẫy hay quên.
Xem thật: bốn dòng, bốn màu
Đặt bốn thẻ ở bốn trạng thái khác nhau và mở list:

Hình 2: Cùng list ở Hình 1, render thật. Mỗi dòng một màu theo đúng điều kiện: VIP-0003 (150đ) xanh đậm (success + bf cùng áp vì 150 ≥ 100 và ≥ 150); VIP-0001 (120đ) xanh; VIP-0002 (hết hạn) cam; VIP-0004 (đã khoá) đỏ. Nhìn màu là biết ngay dòng nào cần xử lý — không cần đọc cột trạng thái.
Điểm hay ở VIP-0003: hai decoration cùng áp (success cho màu xanh, bf cho in đậm) vì cả hai biểu thức đều đúng — cho ra "xanh đậm". Decoration ghép được với nhau.
Bảng màu decoration đầy đủ
| decoration | Kiểu | Thường dùng cho |
|---|---|---|
success |
Xanh lá | Trạng thái tốt, hoàn tất, đạt ngưỡng |
info |
Lam | Thông tin, đang xử lý |
warning |
Cam | Cảnh báo, sắp hết hạn |
danger |
Đỏ | Lỗi, bị khoá, quá hạn |
muted |
Xám mờ | Không hoạt động, rỗng, đã lưu trữ |
bf |
In đậm | Nhấn mạnh (ghép với màu) |
it |
Nghiêng | Ghi chú, tạm |
Các màu (success/info/warning/danger/muted) là màu chữ; bf/it là kiểu chữ — nên hay ghép một màu với bf để vừa tô vừa nhấn.
Cạm bẫy và lưu ý
- Field trong biểu thức phải có trong list. Nếu
decoration-danger="trang_thai == 'khoa'"mà cộttrang_thaikhông được khai trong list, biểu thức không đọc được giá trị. Nếu không muốn hiện cột đó, thêm<field name="trang_thai" column_invisible="1"/>— ẩn cột nhưng vẫn nạp. - Nhiều decoration cùng đúng thì cùng áp, nhưng nếu hai màu chữ cùng đúng, cái sau (theo thứ tự ưu tiên CSS) thắng — nên tránh cho hai màu chồng nhau trên cùng dòng; thiết kế điều kiện loại trừ.
- Biểu thức là Python trên field của dòng, dùng
== != > < >= in not in and or not— giốnginvisible/readonlyở bài trước. - Decoration chỉ đổi hình thức, không lọc. Muốn ẩn dòng thì dùng domain của action/filter, không phải decoration.
Ba ý mang về
decoration-<màu>="biểu thức"tô màu/kiểu từng dòng list theo điều kiện Python trên field của dòng — không cần JavaScript. Đã chứng minh: 4 thẻ ra 4 màu (xanh đậm / xanh / cam / đỏ) đúng điều kiện.- Bảy giá trị:
success(xanh),info(lam),warning(cam),danger(đỏ),muted(xám) là màu chữ;bf(đậm),it(nghiêng) là kiểu — ghép được (nhưsuccess+bf= xanh đậm). - Cạm bẫy: field dùng trong biểu thức decoration phải có trong list (dùng
column_invisible="1"nếu không muốn hiện cột); decoration chỉ đổi hình thức, không lọc dòng.
Ta đã tô màu và điều khiển hiển thị field. Lần sau đi vào chính cái ô field: Phần sau mổ xẻ widget trên trường — chọn đúng widget (badge, monetary, progressbar, handle, priority...) để mỗi field vừa đẹp vừa đúng chức năng.