Skip to content

Odoo with_context() Patterns: Context Manipulation Guide

DeployMonkey Team · March 24, 2026 10 min read

What is Context in Odoo?

The context is a dictionary attached to every Odoo environment that carries metadata about the current operation — language, timezone, active company, default values, and behavior flags. with_context() creates a new environment with modified context values, allowing you to control how ORM operations behave.

Basic Usage

Adding Context Values

# Add or override context keys
records = self.with_context(my_flag=True).search([])

# Multiple values
records = self.with_context(
    default_partner_id=partner.id,
    tracking_disable=True,
).create(vals)

Reading Context

# In any method
partner_id = self.env.context.get('default_partner_id')
is_import = self.env.context.get('import_compat', False)
lang = self.env.context.get('lang', 'en_US')

Common Context Keys

KeyPurposeExample
langTranslation language'fr_FR', 'de_DE'
tzTimezone'Europe/Paris'
allowed_company_idsMulti-company access[1, 2, 3]
active_testInclude archived recordsFalse to include
tracking_disableDisable chatter trackingTrue during imports
mail_create_nologNo creation log messageTrue for silent creates
mail_notrackDisable field trackingTrue for batch writes
import_compatImport mode flagTrue during data import
force_companyForce specific companycompany_id integer

Default Values via Context

The most common use — pre-fill fields when creating records:

# In Python
self.with_context(
    default_type='out_invoice',
    default_partner_id=customer.id,
    default_journal_id=journal.id,
).env['account.move'].create({})

# In XML action
<field name="context">{
    'default_type': 'out_invoice',
    'default_partner_id': active_id,
}</field>

Any context key starting with default_ automatically sets the corresponding field's default value during create.

Language Switching

# Get product name in French
product_fr = product.with_context(lang='fr_FR')
french_name = product_fr.name

# Write translated value
product.with_context(lang='fr_FR').write({
    'name': 'Nom en français',
})

# Send email in partner's language
partner_lang = partner.lang or 'en_US'
template.with_context(lang=partner_lang).send_mail(record.id)

Controlling Mail Behavior

# Silent create — no chatter messages at all
record = self.with_context(
    mail_create_nolog=True,
    mail_create_nosubscribe=True,
    tracking_disable=True,
).create(vals)

# Silent write — no tracking messages
record.with_context(tracking_disable=True).write({
    'state': 'done',
})

# No auto-subscribe on create
record = self.with_context(
    mail_create_nosubscribe=True,
).create(vals)

These are essential for bulk imports and data migration where thousands of tracking messages would slow everything down.

Active Records Filtering

# Default: only active records
active_partners = self.env['res.partner'].search([])

# Include archived records
all_partners = self.env['res.partner'].with_context(
    active_test=False,
).search([])

# Search specifically for archived
archived = self.env['res.partner'].with_context(
    active_test=False,
).search([('active', '=', False)])

Multi-Company Context

# Switch to a specific company's context
records = self.with_context(
    allowed_company_ids=[target_company.id],
).env['sale.order'].search([])

# Access records from multiple companies
records = self.with_context(
    allowed_company_ids=[company_a.id, company_b.id],
).env['sale.order'].search([])

Custom Context Flags

Create your own context flags to control behavior:

# Set a flag
record.with_context(skip_validation=True).write(vals)

# Check the flag in a constraint or override
@api.constrains('amount')
def _check_amount(self):
    if self.env.context.get('skip_validation'):
        return
    for record in self:
        if record.amount < 0:
            raise ValidationError("Amount must be positive.")

Common Pitfalls

  • Context is immutablewith_context() returns a NEW recordset with the new context. The original is unchanged. You must use the returned value.
  • Context accumulation — Nested with_context calls accumulate keys. If a key is set upstream, it persists downstream unless explicitly overridden.
  • Performance — Each with_context() call creates a new Environment object. Avoid calling it in tight loops.
  • Security — Never trust context values from the client (they can be manipulated). Validate context flags in server-side code.
  • active_test trap — Forgetting active_test=False when searching for archived records is a common source of "record not found" errors.