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.