Nhìn khắp Odoo, chỗ nào có "người phụ trách", "người tạo", "khách hàng" — bạn hay thấy một avatar tròn nhỏ đứng cạnh cái tên. Đó không phải mỗi nơi tự vẽ, mà là một widget sẵn có: many2one_avatar. Hai bài trước ta viết widget; bài này cho thấy Odoo đã có sẵn nhiều widget rất hữu dụng — dùng chúng, bạn khỏi viết gì.

Một field, hai cách hiển thị

Một field Many2one (quan hệ tới bản ghi khác) mặc định chỉ hiện tên bản ghi liên quan. Nhưng nếu bản ghi đó có ảnh (như res.partner, res.users), many2one_avatar hiển thị ảnh + tên — trực quan hơn hẳn:

Ảnh chụp đoạn mã Odoo 19 nền tối. Phần trên chú thích dùng widget sẵn có không viết JS chỉ khai widget, một field partner_id thường chú thích Many2one chỉ hiện tên, rồi field partner_id widget many2one_avatar chú thích cộng avatar của bản ghi liên quan res partner có ảnh. Phần dưới liệt kê các biến thể sẵn có của Odoo 19 gồm many2one_avatar avatar và tên, many2one_avatar_user cho res users bấm avatar mở chat hồ sơ, many2one_avatar_employee cho hr employee nhân viên, many2one_avatar_resource cho tài nguyên lịch dự án, và ghi chú họ many2many cũng có many2many_avatar_user many2many_tags_avatar, cùng chú thích nếu không ảnh widget tự vẽ avatar chữ cái làm mặc định

Hình 1: Chỉ một thuộc tính widget="many2one_avatar" trên <field> — không một dòng JS. Odoo có sẵn cả họ widget avatar: many2one_avatar (bản ghi bất kỳ có ảnh), many2one_avatar_user (user, bấm avatar mở chat/hồ sơ), many2one_avatar_employee (nhân viên), many2one_avatar_resource. Còn có họ many2many (many2many_avatar_user, many2many_tags_avatar) cho quan hệ nhiều-nhiều.

Kết quả thật, và cái hay khi không có ảnh

Mình gắn many2one_avatar cho partner_id (chủ thẻ) trên thẻ kanban:

Ảnh chụp thật bảng kanban thẻ thành viên Odoo 19 nhóm theo hạng thẻ. Thẻ VIP-0001 và VIP-0002 có chủ thẻ Nguyễn Văn An hiển thị một avatar hình tròn màu hồng với chữ N ở giữa vì chủ thẻ chưa có ảnh. Thẻ VIP-0003 và VIP-0004 chưa gán chủ thẻ nên hiển thị một biểu tượng người kèm dấu cộng màu xám làm chỗ trống. Bên phải mỗi thẻ có huy hiệu hạng Bạc hoặc Vàng, dưới có dòng điểm kèm ngôi sao

Hình 2: Widget render thật. VIP-0001, VIP-0002 (chủ thẻ "Nguyễn Văn An", chưa có ảnh) hiện avatar-chữ-cái "N" — widget tự vẽ chữ đầu tên trên nền màu khi bản ghi không có ảnh, nên không bao giờ trống trơn. VIP-0003, VIP-0004 (chưa gán chủ thẻ) hiện icon "thêm người" — chỗ trống rõ ràng. Cùng cái avatar bạn thấy khắp Odoo, giờ trên thẻ của mình, không tốn công vẽ.

Chọn biến thể cho đúng

Các biến thể khác nhau ở kiểu bản ghi và hành vi khi bấm:

  • many2one_avatar — tổng quát, cho mọi model có ảnh (res.partner, model của bạn có image_128). Chỉ hiện, không hành vi đặc biệt.
  • many2one_avatar_user — cho res.users. Bấm vào avatar mở thẻ liên hệ/chat với người đó — tiện cho field "người phụ trách".
  • many2one_avatar_employee — cho hr.employee, tích hợp với module Nhân sự.
  • Field liên quan phải có ảnh (một field image như avatar_128/image_128) để widget lấy; không có thì rơi về avatar-chữ-cái.

Dùng đúng biến thể để có đúng hành vi: many2one_avatar_user cho một field trỏ tới user sẽ cho người dùng bấm-để-chat, thứ mà many2one_avatar trơn không có.

Bài học rộng hơn: đọc kho widget trước khi tự viết

Điều đáng nhớ không phải riêng avatar, mà là: Odoo có sẵn hàng chục widget — badge, priority, boolean_toggle, progressbar, handle, image, many2many_tags, monetary... Trước khi ngồi viết một field widget (như bài adv-137), hãy tra kho có sẵn trong web/static/src/views/fields/. Rất thường thứ bạn cần đã có, chỉ chờ một chữ widget="...".

Ba ý mang về

  1. many2one_avatar hiển thị một field Many2one kèm ảnh đại diện của bản ghi liên quan — chỉ cần widget="many2one_avatar" trên <field>, không viết JS. Không ảnh thì widget tự vẽ avatar-chữ-cái, không bao giờ trống.
  2. Có biến thể theo kiểu bản ghi và hành vi: many2one_avatar_user (user, bấm mở chat), many2one_avatar_employee (nhân viên), many2one_avatar_resource, cùng họ many2many_avatar_*. Chọn đúng để có đúng hành vi.
  3. Tra kho widget sẵn có trước khi tự viết. Odoo có hàng chục widget dựng sẵn (badge, priority, progressbar, image...) trong web/static/src/views/fields/; phần lớn nhu cầu đã có, chỉ chờ một chữ widget=.

Nhắc tới field đặc biệt — phần sau mổ field Html: cách Odoo nhúng trình soạn thảo văn bản đầy đủ vào một field, và cách tùy biến nó (thu gọn thanh công cụ, đổi bộ nút cho phép).