How to Using request.env Safely in Controllers in Odoo?
✅ What is request.env?
In Odoo’s web controller architecture (http.Controller), request.env is used to access the Odoo ORM environment from HTTP routes.
from odoo.http import request
partner = request.env['res.partner'].browse(partner_id)
It’s equivalent to self.env in models, but in controllers, it's accessed via the global request object.
🛡 Why "Safe Use" Matters
Accessing request.env without care may:
- Expose sensitive data
- Bypass permissions
- Lead to wrong company context
- Create security vulnerabilities if sudo() is misused
⚙️ Common Use Cases
✅ Safe Access (Portal user or authenticated)
@http.route('/my/orders', auth='user', type='http', website=True)
def portal_orders(self):
partner = request.env.user.partner_id
orders = request.env['sale.order'].search([('partner_id', '=', partner.id)])
return request.render('my_module.portal_orders_template', {'orders': orders})
- Authenticated via auth='user'
- Uses current user’s access rights
- request.env.user returns the logged-in user
🔐 When to Use sudo() (and When Not To)
🔸 Example: Safe Use of sudo()
@http.route('/api/public-data', type='json', auth='public', csrf=False)
def get_data(self):
records = request.env['res.country'].sudo().search([])
return [rec.name for rec in records]
- OK for public models like countries, states, product categories
- Avoid sudo() on sensitive models (e.g., res.users, account.move)
❌ What to Avoid
🚫 Unrestricted sudo() on sensitive models
request.env['res.users'].sudo().search([])
- This bypasses ACLs and may expose all users or private data
- Always validate access before using sudo() in APIs
🔄 Ensuring Company Context
In multi-company setups, request.env respects the session’s company.
If you must force a company context:
request.env.with_company(company).['model'].search([])
🔍 Pattern: Token-authenticated API Using sudo() Correctly
@http.route('/api/customer/data', type='json', auth='none', csrf=False)
def customer_data(self, token=None):
if not token or token != 'expected_token':
return {'error': 'Unauthorized'}
# safe sudo access for limited purpose
partner = request.env['res.partner'].sudo().search([('email', '=', 'abc@example.com')], limit=1)
return {'name': partner.name} if partner else {'error': 'Not found'}
✅ Summary Table
Best Practice | Recommendation |
Use auth='user' where possible | ✅ Safe and uses logged-in user rights |
Avoid sudo() unless needed | ✅ Use with controlled models/data |
Don't expose sensitive models | 🚫 e.g., res.users, account.*, ir.* |
Validate access if public | ✅ Use tokens, API keys, or partner checks |
Use with_company() if required | ✅ For specific company context override |
🧠 Final Tips
- Avoid using sudo() just to “make it work” — it’s not a fix, it’s a risk.
- In APIs or public routes, always sanitize inputs and check authentication.
- For portal routes, prefer auth='user' and use request.env.user responsibly.