Ở bài trước, display_name quyết định bản ghi hiện ra thế nào. Bài này là mặt còn lại: khi người dùng gõ để tìm trong ô Many2one, Odoo khớp theo trường nào? Mặc định chỉ trường định danh. Nhưng thực tế bạn thường muốn tìm được cả bằng thông tin liên quan — ví dụ gõ tên khách để ra thẻ của họ. Đó là việc của _rec_name và _rec_names_search.

Hai thuộc tính, hai vai trò

  • _rec_name: trường định danh của model (mặc định là name). display_name và tìm kiếm cơ bản lấy từ đây. Nếu trường định danh của bạn tên khác (ví dụ ma_so), phải khai _rec_name = 'ma_so'.
  • _rec_names_search: danh sách các trường mà tìm kiếm gợi ý sẽ khớp — mở rộng ra ngoài trường định danh, kể cả xuyên quan hệ.

_rec_name và name_search trong Odoo 19 gõ tìm bản ghi khớp theo trường nào: _rec_name là trường định danh mặc định name, class TheThanhVien khai _rec_name bằng name để display_name và tìm kiếm lấy từ đây, nếu trường định danh không tên name như ma_so thì phải khai _rec_name; _rec_names_search mở rộng trường được tìm ở Odoo 19, khai _rec_names_search bằng list name và partner_id.name để gõ trong ô Many2one khớp cả mã thẻ lẫn tên khách hàng; cần logic phức tạp thì override _search_display_name self operator value trả về domain tìm kiếm tuỳ ý ví dụ hoặc name operator value hoặc partner_id.name operator value, name_search API cũ vẫn còn nhưng _rec_names_search gọn hơn

Hình 1: _rec_name chọn trường định danh; _rec_names_search = ['name', 'partner_id.name'] bảo Odoo khi gõ tìm thì khớp cả mã thẻ lẫn tên khách. Cần logic phức tạp thì override _search_display_name(operator, value) để tự dựng domain. (name_search API cũ vẫn còn nhưng _rec_names_search gọn hơn hẳn.)

Chạy thật — tìm bằng tên khách

Tôi thêm _rec_names_search = ['name', 'partner_id.name'] vào model quan.the.thanh.vien, nâng cấp, rồi tìm thử. Output thật trên db blog19:

Output name_search chạy thật trên module quan_ca_phe database blog19: đã khai _rec_names_search bằng list name và partner_id.name, T._rec_name trả name, T._rec_names_search trả list name và partner_id.name; thẻ ABC-123 gắn khách Nguyễn Minh Anh, mã thẻ không chứa tên khách, the.display_name trả ABC-123 Vàng gạch Nguyễn Minh Anh; gõ theo mã thẻ T.name_search ABC trả ABC-123 Vàng Nguyễn Minh Anh; gõ theo tên khách T.name_search Nguyễn khớp nhờ partner_id.name trong _rec_names_search trả VIP-0001 Bạc Nguyễn Văn An và ABC-123 Vàng Nguyễn Minh Anh; không khai partner_id.name thì gõ tên khách sẽ không ra thẻ nào

Hình 2: Output thật. Thẻ ABC-123 gắn khách "Nguyễn Minh Anh" — mã thẻ không chứa tên khách. Gõ 'ABC' (mã thẻ) → ra thẻ đó. Và điểm mấu chốt: gõ 'Nguyễn' (tên khách) cũng ra các thẻ — VIP-0001 và ABC-123 — nhờ partner_id.name có trong _rec_names_search. Không khai nó thì gõ tên khách sẽ không ra thẻ nào.

Vì sao hữu ích?

Đây là trải nghiệm người dùng thực tế. Nhân viên quầy nhớ tên khách, không nhớ mã thẻ. Khi chọn thẻ trong một form (ví dụ tạo giao dịch điểm), họ gõ tên khách và muốn ra ngay thẻ đúng. _rec_names_search biến điều đó thành hiện thực chỉ với một dòng.

Nhìn rộng ra, cùng cơ chế này giải thích vì sao trong Odoo bạn gõ email vào ô "Khách hàng" vẫn ra đúng người, hay gõ mã sản phẩm vào ô "Sản phẩm" vẫn khớp — các model đó khai thêm trường vào tìm kiếm.

_search_display_name — khi cần logic

Nếu muốn kiểm soát hoàn toàn (ưu tiên khớp mã trước, hay ghép điều kiện phức tạp), override _search_display_name để tự trả về domain:

def _search_display_name(self, operator, value):
    # Tìm theo mã thẻ HOẶC tên khách
    return ['|', ('name', operator, value), ('partner_id.name', operator, value)]

Method này nhận operator (ilike, =...) và value (chuỗi người dùng gõ), trả về domain. Đây là cách linh hoạt nhất, tương đương override name_search kiểu cũ nhưng đúng chuẩn Odoo 19.

Lưu ý

  • Xuyên quan hệ tốn hơn: partner_id.name sinh JOIN; nhiều trường xuyên sâu làm tìm kiếm nặng. Chỉ thêm trường thật cần.
  • Trường phải tồn tại: khai sai tên trường trong _rec_names_search sẽ lỗi lúc tìm.
  • Khác display_name: _rec_names_search là trường để tìm (input), display_name là chuỗi để hiện (output) — hai thứ độc lập, thường khai cùng nhau cho nhất quán.

Nhớ ba ý

  1. _rec_name chọn trường định danh (mặc định name; đổi tên trường thì phải khai); _rec_names_search mở rộng các trường mà tìm kiếm gợi ý khớp — kể cả xuyên quan hệ.
  2. Đo thật: _rec_names_search = ['name', 'partner_id.name'] cho gõ 'Nguyễn' (tên khách) ra đúng thẻ; không khai thì gõ tên khách không ra gì.
  3. Cần logic phức tạp → override _search_display_name(operator, value) trả về domain (chuẩn Odoo 19, thay name_search cũ).

Tìm và hiển thị bản ghi xong, một câu hỏi cơ bản còn lại: danh sách bản ghi mặc định sắp xếp thế nào? Phần sau đi vào _order — đặt thứ tự sắp xếp mặc định cho model, và ảnh hưởng của nó tới hiệu năng truy vấn.