Introduction
Every form in Odoo has fields. Some need to be filled in manually every time. But many fields can be given a sensible default value so users start with something useful already in place. The default value mechanism in Odoo is simple on the surface but has several layers worth understanding, especially when you are configuring or customizing forms for your team.
Whether you are a business user adjusting a field through Odoo Studio or a developer working through an odoo field tutorial, knowing how defaults work saves time and prevents the kind of silent configuration mistakes that are hard to diagnose later.
This guide covers what default values are in Odoo, how they work at the ORM level, when to use static versus dynamic defaults, and how to configure them through Odoo Studio or Python code.
What is the Default Value in Odoo
In the Odoo ORM, a default value is what gets assigned to a field when a new record is created, before the user fills anything in. It is not a constraint. The user can change it freely. It is simply a starting point that makes the form more useful out of the box.
The default parameter is available on virtually every field type in the Odoo framework: Char, Integer, Float, Boolean, Date, Many2one, Selection, and others. It can be a plain value, a Python lambda, or a method reference. All of these count as valid default mechanisms depending on the use case.
In Odoo Studio, default values appear in the field properties panel as a simple input. Business users can set a static default without writing any code. This makes it one of the most accessible ways to improve data consistency using Odoo Studio fields, without requiring developer involvement.
At the database level, defaults are not stored in the field column itself. They live either in the Python model definition or in ir.default records in the database, depending on how they were configured. When a new record is created, Odoo reads those defaults and pre-fills the form before the user sees it.
How the Default Value Works
When a user opens a new form in Odoo, the framework calls default_get() on the model. This method collects all field defaults and returns a dictionary mapping field names to their default values. The form then pre-fills those fields before the user does anything.
There are four main types of default values in Odoo, each covering a different scenario.
Static Defaults
A fixed value hardcoded in the field definition or set through Studio. For example, setting a Boolean field to True by default, or a Selection field to 'draft'. These are the simplest kind and cover most everyday use cases in an Odoo data model.
Dynamic Defaults via Lambda or Method
A Python function or lambda that runs at record creation time. This allows defaults that depend on the current date, the logged-in user, or any other available context. For example, setting the current user as the default responsible person, or using today as the default document date.
Here is how static and dynamic defaults look in a Python model definition, following the standard odoo development pattern:
from odoo import fields, models
class CrmLead(models.Model):
_inherit = 'crm.lead'
# Static default
x_priority_level = fields.Selection(
[('low', 'Low'), ('medium', 'Medium'), ('high', 'High')],
string='Priority Level',
default='medium',
)
# Dynamic default: current user
x_assigned_by = fields.Many2one(
'res.users',
string='Assigned By',
default=lambda self: self.env.user,
)
# Dynamic default: today's date
x_expected_date = fields.Date(
string='Expected Close Date',
default=lambda self: fields.Date.today(),
)
Context-Based Defaults
Values passed through the action context using the default_field_name convention. When you click Create from inside a related record, Odoo often passes context values that become defaults for relational fields. For example, opening a new task from inside a project automatically sets the project field. This is part of how navigation flows work in the Odoo framework and it is driven entirely by context keys that any developer or advanced user can configure.
User-Level Defaults via ir.default
Odoo also supports user-specific defaults through ir.default records. An administrator can configure a personal default for a given field on a given model. When that user creates a new record, their personal default takes precedence over the model-level default. This is useful in multi-user environments where different team members have different working preferences, and it is one of the lesser-known capabilities of the odoo orm.
Priority Order
When multiple default sources exist for the same field, Odoo resolves them in this order: user-specific ir.default first, then company-level ir.default, then the default defined in the Python model. Context-based defaults passed at runtime also override model-level defaults. Knowing this order helps you understand why a field might not be showing the value you expect when you open a new form.
Business Use Cases
Default values appear across virtually every module in an Odoo implementation. Here are five practical examples from real business workflows.
CRM: Default Salesperson on New Leads
When a salesperson creates a new lead or opportunity, the Responsible field defaults to the current user. This avoids every lead starting unassigned and requiring manual attribution. The default is set with lambda self: self.env.user in the model definition. In practice, this small detail improves CRM adoption because users immediately see their own leads without any extra step.
Sales: Default Payment Terms on Orders
When a sale order is created for a customer, fields like pricelist and payment terms default based on the customer partner configuration. A customer set up with Net 30 payment terms will have those terms pre-filled on every new order. This reduces manual selection errors and ensures that the terms agreed with each customer are applied consistently, even when different salespeople create the orders.
Inventory: Default Locations on Transfers
When creating an internal transfer or inventory adjustment, the source and destination location fields default to the locations configured in the warehouse settings. Warehouse staff who always work within the same zone will find the correct location already selected when they open a new transfer. This saves clicks and reduces the risk of selecting the wrong location under time pressure.
Accounting: Default Journal on Entries
When a user creates a new customer invoice or vendor bill, Odoo defaults to the appropriate journal based on the entry type and company configuration. An accountant opening a new vendor bill does not have to select the purchase journal manually every time. The default is resolved dynamically from company settings, not from a hardcoded value, which means it stays correct even if journals are reconfigured later.
Project: Default Stage on New Tasks
When a new task is created inside a project, it starts in the first stage of that project kanban configuration. If the task is created by clicking a button on a specific project record, context-based defaults also pre-fill the project and sometimes the assignee. Teams using Odoo for project management benefit from these defaults because it keeps new tasks in the right place from the moment they are created, without any manual setup.
Creating or Customizing Default Values
There are three main approaches to setting default values in Odoo, ranging from a no-code click-through in Studio to full Python control in a custom module.
Using Odoo Studio (No Code)
Odoo Studio provides a visual interface for setting default values on any field in your forms. To set a default through Studio:
- Open the Studio interface on the form you want to modify
- Click on the field you want to configure
- In the field properties panel on the right, find the Default Value input
- Enter or select the value you want as the starting default
- Save and exit Studio
Studio stores this configuration as an ir.default record in the database. It applies company-wide unless an administrator specifies a user-level restriction. This approach works well for static defaults on Selection, Boolean, Char, and Integer fields. For Many2one fields, Studio lets you pick an existing record from a dropdown. It is one of the most practical uses of create fields odoo without writing any code.
One thing to keep in mind: changing the default through Studio after users have already been creating records does not update those existing records. The new default only applies to records created after the change.
Using Python in Technical Customization
For technical odoo customization, defaults are set directly in the field definition inside the Python model. This gives full control over static values, dynamic lambdas, and method-based defaults. It is the preferred approach in any odoo development scenario where the default depends on runtime information like the current user, today date, or company configuration.
Here is an example showing several types of defaults you might add to a custom module:
from odoo import fields, models
class SaleOrder(models.Model):
_inherit = 'sale.order'
# Static Boolean default
x_requires_review = fields.Boolean(
string='Requires Review',
default=False,
)
# Static Selection default
x_delivery_preference = fields.Selection(
[('standard', 'Standard'), ('express', 'Express')],
string='Delivery Preference',
default='standard',
)
# Dynamic default using a method
def _default_note(self):
return self.env['ir.config_parameter'].sudo().get_param(
'sale.default_note', default=''
)
x_internal_note = fields.Text(
string='Internal Note',
default=_default_note,
)
This pattern follows the standard odoo python fields convention and works across all odoo field types. The method-based default is particularly useful when the logic is more complex than a single lambda expression.
Using ir.default Records Programmatically
You can also create or update ir.default records through the Odoo XML-RPC API or within a module data file. This is useful when shipping a default configuration as part of a custom module installation. The ir.default model accepts a model name, a field name, a value, and optionally a company or user to scope the default.
This approach is less common in day-to-day development but comes up when building installable Odoo modules that need to configure sensible defaults as part of their setup routine.
Best Practices for Default Values in Odoo
Set Defaults on Required Fields
If a field is mandatory, give it a sensible default wherever possible. This reduces friction and prevents save errors when users try to submit a new record without realizing a field is required. Combining required=True with a practical default is a good pattern across the odoo data model.
Use Lambdas for Date Defaults
Never hardcode a date as a default value. Use lambda self: fields.Date.today() so the default is always the current date at the moment the record is created. A hardcoded date would be wrong for any record created after the code was written, which in practice means it is wrong almost immediately.
Keep Default Logic Lightweight
Default functions run during record creation, which means they run every time a user opens a new form. Avoid making database queries, calling external APIs, or running heavy computations inside default methods. Keep them fast and simple. If you need something more involved, consider using an onchange or a compute field triggered by another field instead.
Use Context Defaults for Navigation Flows
When building custom actions or smart buttons that open a new form, pass default_field_name values through the action context rather than relying on static model defaults. This is exactly how native Odoo buttons work and keeps your odoo customization aligned with the framework conventions.
Test Defaults with Multiple User Profiles
Dynamic defaults that reference self.env.user or self.env.company behave differently depending on who is logged in. Always test with at least two different user accounts, and with different company configurations if you are running a multi-company setup. What works for an administrator may produce unexpected results for a standard user.
Common Pitfalls
Using a Mutable Object as a Default
This is the classic Python mistake and it applies in Odoo development too. Never write default=[] or default={} for a field. Python shares the same list or dictionary object across all instances, which causes data to bleed between records in unexpected ways. Use a lambda instead: default=lambda self: []. This creates a fresh object each time a record is initialized.
Defaults Do Not Trigger onchange
Setting a default value does not fire onchange methods. If your form has an onchange on a field that normally triggers updates on other fields, the default bypasses that chain reaction entirely. Users will see the pre-filled value but none of the downstream effects that onchange would normally produce. If you need the onchange to run on initialization, you need to call it explicitly in a custom default_get override or handle the logic a different way.
Conflicting Defaults from ir.default and Model Definition
If you set a default both in Python and through Studio or an ir.default record, Odoo resolves them with a priority order. The ir.default record takes precedence over the model-level Python default. This is a common source of confusion when debugging unexpected field values, especially after a Studio configuration change that quietly overrides something a developer set in code.
Assuming a Default Means a Required Value
A field with a default value is not automatically required. If the user clears the field, it will be saved empty. Do not rely on the default alone to enforce data completeness. If you always need a value in that field, combine the default with required=True.
Hardcoding Company or User Record IDs
A default like default=1 referencing a user or company by its database ID is fragile. It will break in any environment where that record has a different ID, which is virtually every production database that was not set up identically to the development environment. Always use dynamic references: lambda self: self.env.company.id or lambda self: self.env.ref('module.xml_id').id.
Conclusion
Default values are a small but powerful feature in the Odoo data model. They reduce manual data entry, guide users toward consistent choices, and make forms easier to use for everyone on the team. Whether you configure them through Odoo Studio for a quick no-code change or define them in Python as part of a technical customization, understanding how defaults work helps you build better Odoo implementations.
The key points to keep in mind: defaults only run at record creation time, not continuously. They do not trigger onchange methods. Multiple default sources follow a defined priority order. And mutable objects like lists or dictionaries should always be wrapped in a lambda when used as field defaults.
Getting defaults right is often the difference between a form that feels intuitive and one that creates friction for users every time they need to create a new record. It is a small investment that pays off every day.
At Dasolo, we help companies implement, customize, and optimize Odoo to fit their specific workflows. If you need help configuring field defaults, building custom fields, or designing an Odoo data model that actually works for your team, we would be happy to assist. Reach out to us and let us talk about your Odoo implementation.