Mỗi request tới controller là một lần chạy độc lập — hàm chạy xong là quên hết. Vậy làm sao một giỏ hàng "nhớ" được món bạn thêm ở request trước? Và trong hàm controller, cái request.env bạn gọi để đọc ORM từ đâu ra, ai là "user hiện tại"? Hai câu hỏi này dẫn tới hai đối tượng cốt lõi mà mọi controller đều dựa vào: request.env (cửa vào ORM, dựng theo auth) và request.session (bộ nhớ giữa các request). Bài này mổ xẻ cả hai và chỉ cách dùng đúng — kiểm chứng bằng một bộ đếm session thật tăng dần qua từng lần gọi.

request.env: cửa vào ORM, dựng theo auth

Trong controller, request.env là một Environment đầy đủ như trong code model — nhưng nó được dựng riêng cho request này, dựa trên phiên và auth của route. Ba mảnh quan trọng:

  • request.env.user / request.env.uid — người dùng hiện tại. Ai là "hiện tại" phụ thuộc auth: auth='user' là người đã đăng nhập, auth='public' là "Public user", auth='none' thì uid=None.
  • request.env.cr — con trỏ CSDL (cursor); request.env.cr.dbname là tên database.
  • request.env.context — context: lang, tz... lấy từ session/người dùng.

Ảnh chụp mã Python nền tối. Phần request env: route http qcp_env user auth user, hàm env_user đọc request env user chú thích user hiện tại theo auth, request env uid id user, request env cr con trỏ CSDL, request env cr dbname tên database, request env context context lang tz. Tạo env khác chạy quyền user khác thêm context: env2 bằng request env user bằng partner id context lang en_US, hoặc request update_env user context. Phần request session: session là dict lưu ở filestore theo cookie session_id, dem bằng request session get qcp_dem 0 cộng 1, request session qcp_dem bằng dem ghi vào session, lần request sau cùng cookie đọc lại được đếm tăng, return dict user request env user name db request env cr dbname so_lan_vao dem. Ghi chú auth public thì env user Public user, auth none thì uid None, giá trị ghi vào session phải JSON serializable số chuỗi list dict

Hình 1: request.env cho bạn ORM (env.user, env.cr, env.context); gọi request.env(user=..., context=...) hay request.update_env(...) để tạo một env khác (chạy quyền user khác, thêm context). Phần dưới: request.session là một dict giữ trạng thái — ghi session['qcp_dem'] rồi request sau đọc lại được.

request.session: bộ nhớ giữa các request

request.session là một dict đặc biệt: những gì bạn ghi vào nó sống sót qua các request của cùng một khách. Odoo lưu session trên đĩa (filestore), nhận diện bằng cookie session_id mà trình duyệt tự gửi kèm mỗi lần. Nhờ vậy session['gio_hang'], session['buoc_wizard']... nhớ được trạng thái mà không cần bảng CSDL.

Chạy thật: một route auth='user' đọc env.user, env.cr.dbname, và tăng một bộ đếm trong session. Gọi ba lần trong cùng phiên:

Ảnh chụp terminal nền tối kết quả thật trên Odoo 19 cùng một phiên đăng nhập admin. GET qcp_env user ba lần cùng cookie session_id: lần đầu trả về env_user Administrator, env_uid 2, db blog19, lang vi_VN, so_lan_vao 1; lần hai so_lan_vao 2; lần ba so_lan_vao 3 kèm chú thích session giữ số tăng qua từng request. GET qcp_env public auth public trả về env_user Public user env_uid 3. Ghi chú env user đổi theo auth, session bền giữa các request nhờ cookie

Hình 2: env.user là "Administrator" (uid 2), db là "blog19", lang "vi_VN" — tất cả từ request.env. Và so_lan_vao tăng 1 → 2 → 3 qua từng request: session nhớ giá trị giữa các lần gọi (nhờ cookie session_id). Route auth='public' cho thấy env.user là "Public user" (uid 3) — env đổi theo auth.

Cơ chế: env dựng từ session

Hai thứ này không rời rạc — request.env được dựng từ session. Nhìn lõi Odoo 19:

Ảnh chụp mã Python nền tối file http py Odoo 19 env dựng từ session session lưu ở filestore. self env bằng odoo api Environment cr self session uid self session context, chú thích auth user session uid là id user thật, auth public _auth_method_public gán Public user, auth none uid None. class Session kế thừa collections abc MutableMapping là một dict với uid id user đã đăng nhập hoặc None, context lang tz, cộng mọi khoá bạn tự đặt như session gio_hang bằng list. Session lưu trên đĩa theo cookie session_id: FilesystemSessionStore path session_class Session renew_missing True

Hình 3: request.env = Environment(cr, session.uid, session.context) — chính session.uid (ai đăng nhập) và session.context (lang/tz) quyết định env. Session là một MutableMapping (dict) lưu trên đĩa qua FilesystemSessionStore, nhận diện bằng cookie. Đó là lý do đổi user hay đổi ngôn ngữ ở một request ảnh hưởng các request sau: chúng cùng đọc một session.

Dùng đúng: vài quy tắc

  • Giá trị ghi vào session phải JSON-serializable — số, chuỗi, list, dict. Đừng nhét recordset hay đối tượng phức tạp vào session; lưu id rồi browse lại khi cần.
  • Đừng lạm dụng session làm CSDL. Session hợp cho trạng thái tạm theo phiên (giỏ hàng chưa đặt, bước wizard); dữ liệu cần bền và truy vấn được thì lưu vào model.
  • request.env(...) tạo env mới, không sửa env cũ. Muốn chạy một đoạn với quyền/context khác thì env2 = request.env(user=..., context=...); request.update_env(...) mới thay đổi env của request hiện tại.
  • Session ẩn danh có thể không bền. Với khách chưa đăng nhập, session đôi khi không được lưu đến khi có gì đó thực sự ghi vào — đây là lý do một số form công khai gặp trục trặc CSRF (token gắn session). Đăng nhập tạo session ổn định.

Ba ý mang về

  1. request.env là ORM dựng riêng cho request theo auth: env.user/env.uid (người hiện tại — thật, Public, hay None), env.cr (cursor, .dbname), env.context (lang/tz); request.env(user=..., context=...) tạo env khác.
  2. request.session là dict giữ trạng thái giữa các request — lưu trên filestore, nhận diện bằng cookie session_id; ghi giá trị JSON-serializable, dùng cho trạng thái tạm (giỏ hàng, wizard).
  3. env được dựng từ session (Environment(cr, session.uid, session.context)) — nên user và ngôn ngữ trong session quyết định env; đừng nhét recordset vào session, lưu id.

Ta đã đi hết controller và session. Phần sau quay lại phía website nhưng ở mức "sống động" hơn: Phần sau làm dynamic snippet — khối kéo–thả lấy dữ liệu sống từ model, hiển thị bản ghi thật (sản phẩm, bài viết) tự cập nhật ngay trên trang, thay vì nội dung tĩnh.