Ở bài recordset ta nói mỗi recordset "mang theo env". Giờ mở hộp đó ra: env là môi trường ORM — nó trả lời câu hỏi "ai đang thao tác, dưới công ty nào, ngôn ngữ gì, trong giao dịch nào". Hiểu env là hiểu bối cảnh mọi lời gọi ORM. Mở màn chương "môi trường & ngữ cảnh", bài này mổ xẻ từng thành phần của env.
env gồm những gì?

Hình 1: env là một object Environment gói sáu thứ chính. env.cr (con trỏ CSDL — chạy SQL thô, quản giao dịch), env.uid/env.user (người dùng hiện tại — nền của phân quyền), env.context (ngôn ngữ, múi giờ, cờ tuỳ biến), env.company (công ty hiện tại — lọc đa công ty), env.su (có đang superuser không). Mọi recordset đều gắn với một env.
Nhìn giá trị thật
Đây là giá trị env thật trong odoo shell trên db blog19:

Hình 2: Giá trị thật. env.uid=1, env.user.name='OdooBot' (shell chạy dưới superuser). env.cr là một Cursor. env.company là "Công ty TNHH Cà Phê Việt". env.context = {'lang':'en_US', 'tz':False, 'uid':1}. Và điểm mấu chốt: recordset rs có rs.env is env = True — nó dùng đúng cùng môi trường. Từ đó gọi model khác (rs.env['res.users']), và env.cr chạy SQL thô trả count=33.
Từng thành phần dùng khi nào
env.cr — con trỏ CSDL
Cho các thao tác sát CSDL: chạy SQL thô (khi ORM không đủ), quản giao dịch. Trong odoo shell bạn gọi env.cr.commit() để lưu.
env.cr.execute("SELECT id FROM res_partner WHERE active = %s", (True,))
rows = env.cr.fetchall() # dùng %s tham số hoá — KHÔNG nối chuỗi (chống SQL injection)
Cảnh báo: SQL thô bỏ qua ORM (không chạy computed, constrains, phân quyền) — chỉ dùng khi thật cần, và luôn tham số hoá.
env.uid / env.user — người dùng
Nền của phân quyền (record rules, access rights). Odoo dùng env.uid để quyết định bạn thấy/sửa được bản ghi nào.
if self.env.user.has_group('base.group_system'):
... # chỉ admin
env.context — ngữ cảnh
Dict truyền tuỳ chọn không thuộc dữ liệu: lang (ngôn ngữ dịch), tz (múi giờ hiển thị), và cờ tuỳ biến để đổi hành vi. Đổi context là chủ đề bài sau.
env.company — công ty hiện tại
Trong hệ đa công ty, quyết định dữ liệu của công ty nào được thấy. env.companies là tập các công ty đang bật.
env đi cùng recordset
Điểm quan trọng nhất về mặt kỹ thuật: recordset gắn chặt với env. Hai recordset cùng model, cùng id, nhưng khác env (khác user, khác company, khác context) là hai thứ khác nhau — cho kết quả khác nhau (phân quyền, ngôn ngữ, computed theo ngữ cảnh).
Từ bất kỳ recordset nào, rec.env cho bạn môi trường đó, và rec.env['model.khac'] gọi sang model khác giữ nguyên ngữ cảnh. Đây là lý do trong method bạn luôn viết self.env[...] chứ không import model trực tiếp.
Vài truy cập hữu ích
self.env.ref('base.group_user') # lấy bản ghi theo XML id
self.env.company # công ty hiện tại
self.env.user # người dùng hiện tại
self.env['ir.config_parameter'].sudo().get_param('...') # đọc cấu hình
self.env.su # có đang superuser?
Nhớ ba ý
envlà môi trường ORM góicr(con trỏ CSDL),uid/user(người dùng),context(lang/tz/cờ),company(công ty),su(superuser) — mọi recordset mang theo.- Đo thật:
rs.env is env= True — recordset dùng đúng env; từ đórec.env['model']gọi model khác giữ ngữ cảnh;env.crchạy SQL thô (nhớ tham số hoá). - Recordset cùng id nhưng khác env là khác nhau (phân quyền/ngôn ngữ/computed theo ngữ cảnh) — luôn dùng
self.env[...]trong code.
env quan trọng nhất ở chỗ đổi được — chạy dưới ngữ cảnh khác. Phần sau đi vào with_context — cách tạo một recordset mới với context thay đổi để đổi ngôn ngữ, múi giờ, hay truyền cờ điều khiển hành vi.