Ở report QWeb phía server, t-out in ra HTML thô — bạn dùng nó để nhúng nội dung có định dạng. Nên khi sang OWL (giao diện trình duyệt), nhiều người quen tay dùng t-out và bất ngờ: nó không render HTML nữa, mà hiện ra nguyên chuỗi <b>...</b> như văn bản. Không phải bug — đó là một hàng rào chống XSS có chủ đích. Bài này dựng demo thật để thấy rõ ba trường hợp, và khi nào HTML mới thật sự được render.
Ba cách đổ dữ liệu vào HTML
Tôi thêm vào dashboard hai giá trị: một chuỗi thường chứa HTML, và một giá trị markup() (đánh dấu là HTML tin cậy), rồi in chúng bằng t-esc và t-out:

Hình 1: Ba cách in. t-esc="state.demo_raw" — luôn escape, biến < > thành thực thể HTML. t-out="state.demo_raw" (chuỗi thường) — cũng escape trong OWL. Chỉ t-out="state.demo_markup" (giá trị đã bọc markup()) mới render thành HTML thật. Phần dưới còn có t-if/t-else chọn nhánh theo state.vang.
Kết quả: chỉ markup mới thành HTML
Render dashboard trong trình duyệt, ba dòng cho ba kết quả khác nhau:

Hình 2: Ba dòng, ba kết quả trên giao diện thật. Dòng 1 (t-esc chuỗi) và dòng 2 (t-out chuỗi) đều hiện nguyên văn <b>Vàng</b> ⭐ — HTML bị escape thành chữ. Chỉ dòng 3 (t-out markup) hiện chữ Vàng in đậm — HTML thật sự được render. Dòng cuối là t-if chạy đúng nhánh (có 1 thẻ Vàng). Chụp bằng trình duyệt thật, không có lỗi Console.
Đối chiếu và lý do bảo mật
Gom lại thành bảng cho dễ nhớ:

Hình 3: t-esc và t-out với chuỗi thường đều escape — an toàn. Chỉ t-out với markup() mới render HTML, và đó là chỗ bạn phải cẩn thận. Lý do thiết kế: chống XSS. Nếu state.demo_raw là tên khách hàng do người dùng nhập, mà nó chứa <script>..., thì escape mặc định khiến nó chỉ hiện thành chữ vô hại. Muốn cho phép HTML, bạn phải chủ động gọi markup() — và khi đó trách nhiệm làm sạch là của bạn.
Vài lưu ý khi làm template OWL
- Mặc định luôn dùng
t-esc(hoặct-outchuỗi). Chỉ bọcmarkup()khi nội dung chắc chắn an toàn (HTML do chính bạn sinh, không phải dữ liệu người dùng). Đừngmarkup()một chuỗi có phần người dùng nhập chưa làm sạch. t-escvst-out: khác biệt chỉ lộ vớimarkup. Với chuỗi/số thường, hai cái cho kết quả y hệt.t-outtồn tại để xử lý được cả markup;t-escthì tuyệt đối không.t-if/t-elif/t-elselà thật của DOM. Nhánh sai không được dựng ra (khácd:none); dùng để bật/tắt cả khối theostate.- Đây khác report QWeb server. Ở report (
_render_qweb_pdf),t-outrender HTML thô. Đừng mang thói quen đó sang OWL — cùng tên chỉ thị nhưng hành vi bảo mật khác.
Ba ý mang về
t-escluôn escape;t-outvới chuỗi thường CŨNG escape trong OWL — chỉt-outvới giá trịmarkup()mới render HTML thật.- Đây là hàng rào chống XSS: dữ liệu (nhất là do người dùng nhập) không bao giờ thành HTML trừ khi bạn chủ động bọc
markup()và tự chịu trách nhiệm làm sạch. t-if/t-elif/t-elsebật/tắt cả khối DOM theostate; và nhớ hành vit-outở OWL khác report QWeb server.
Đổ một giá trị vào HTML thì xong. Nhưng dữ liệu thật thường là danh sách — 4 thẻ, mỗi thẻ một dòng. Phần sau đi vào t-foreach hiển thị danh sách trong OWL: lặp mảng, và vì sao t-key là bắt buộc.