Welcome to this comprehensive Odoo Context Tutorial! If you’re looking to elevate your Odoo development skills, minimize code duplication, and create a truly dynamic user experience, understanding and mastering Odoo’s context mechanism is absolutely crucial. This guide will walk you through practical, step-by-step examples, helping you unlock the full potential of Odoo context.
This tutorial is inspired by and expands upon the valuable insights shared in the video “Discover Odoo Context: Make Your Work Easier” by Amr Gaber. You can find the original video here: https://www.youtube.com/watch?v=7bCZ1ogFjl8
What is Odoo Context and Why is it Essential?
At its core, Odoo context is a dictionary of key-value pairs that carries information about the current state of the application. Think of it as a dynamic message passing system. When you perform an action – opening a view, clicking a button, or creating a new record – Odoo generates a context that can be accessed and manipulated. This powerful feature allows developers to:
- Pass data between different views and models: Share specific values from a parent record to its children or related records without explicit code.
- Implement dynamic behavior: Show or hide fields, columns, or entire sections based on the user’s interaction or the source of navigation.
- Set default values: Pre-populate fields when creating new records, saving users time and reducing errors.
- Apply conditional logic: Modify the behavior of forms, lists, or search filters based on contextual information.
- Reduce code duplication: Instead of creating multiple views or complex Python logic for minor variations, you can leverage context to achieve flexibility within a single view.
For developers aiming to build robust, efficient, and user-friendly Odoo applications, a deep understanding of context is not just an advantage – it’s a necessity. It’s one of the most effective ways to introduce front-end logic and enhance the overall user experience without cluttering your codebase with redundant views.
Prerequisites
To get the most out of this Odoo Context Tutorial, we recommend the following:
- Odoo 18 Community Edition: Our examples are built with compatibility in mind for this version.
- Basic Odoo Development Knowledge: Familiarity with Odoo views (XML), models (Python), and actions is assumed.
- The “School Management” Module: We’ll be using a simple, open-source School Management module for our examples. This module helps manage courses, classes, and students. You can find the link to this module on GitHub in the description of the video mentioned above.
Core Concepts of Odoo Context
Before diving into the practical examples, let’s clarify some fundamental concepts related to Odoo context that you’ll encounter frequently:
- Key-Value Pairs: Context is always a dictionary, meaning it’s composed of
key: valuepairs (e.g.,{'default_gender': 'male'}). - The
parentKeyword: When working with One2many or Many2many relationships in XML, theparentkeyword allows you to access fields from the parent form view. This is incredibly useful for inheriting values. default_*Keys: Odoo has a built-in convention where keys starting withdefault_are automatically used to set default values for fields in a new record. For example,{'default_name': 'New Item'}would set thenamefield to ‘New Item’ when a new record is created.search_default_*Keys: Similar todefault_*,search_default_*keys are used to automatically activate a pre-defined filter in a target search view. The*should match thenameattribute of a filter defined in the search view.context.get()in XML: In Odoo’s XML views, you can directly check for the presence and value of a key in the context using expressions likecontext.get('your_key')within attributes likeinvisibleorreadonly. This is how you implement dynamic behavior based on the incoming context.self.env.context.get()in Python: In your Python models, you can access the current environment’s context usingself.env.context. This allows you to retrieve context values and implement server-side logic based on them.
Now, let’s explore the practical scenarios and solidify your understanding with concrete examples.
Step-by-Step Odoo Context Tutorial: Practical Use Cases
This section provides a hands-on Odoo Context Tutorial covering various scenarios. Each case includes a clear goal, a real-world example, detailed steps, and an explanation of the underlying Odoo mechanics.
1. Passing Values from Form View to Tree/Kanban View (Default Values)
Goal: Automatically pre-fill a field in a One2many or Many2many line item with a value inherited from its parent form view. This significantly improves user efficiency by reducing repetitive data entry.
Example: Imagine a “Course” form with a One2many field for “Course Line Items” (e.g., specific dates or sessions). When a user adds a new line item, we want the “Date” field of that line item to automatically inherit the “Start Date” from the main Course form.
Steps:
- Identify the Target Field: Locate the One2many field definition in your parent model’s view XML file (e.g.,
views/course_views.xml). - Add
contextto the One2many Field: Within the<field>tag of your One2many, include acontextattribute.
<field name="course_line_ids"> <!-- Replace with your actual one2many field name -->
<tree editable="bottom">
<field name="date"/> <!-- This is the field in the child model -->
<!-- Other fields -->
</tree>
<form>
<!-- Form view for child records (if applicable) -->
</form>
<context>{'default_date': parent.start_date}</context>
<!-- 'default_date': target field in child model, 'parent.start_date': field in parent form -->
</field>
- Restart Odoo: After modifying XML, restart your Odoo server to apply the changes.
- Test: Navigate to a Course form. Set a “Start Date”. Then, add a new “Course Line Item”. Observe that the “Date” field in the newly added line is automatically populated with the parent’s “Start Date”. The user can still change it, but the default saves time.
Explanation:
The context attribute on the One2many field passes a dictionary to the context of the related model when a new record is created. The default_ prefix is a special Odoo key that automatically sets the value of the specified field. The parent.start_date expression allows us to dynamically fetch the value from the parent form.
2. Filtering Records in One2many Fields (Domains)
Goal: Dynamically limit the selection options in a Many2one field within a One2many, based on a condition derived from the parent form. This ensures data consistency and a more controlled user workflow.
Example: In a “Class” form, where you add “Students” via a One2many, you might want to filter the available students based on the class’s designated “Gender” (e.g., if the class is for “Male” students, only male students should appear in the selection list).
Steps:
- Locate the Many2one Field: Find the Many2one field within your One2many definition in the view XML (e.g., the
student_idfield inside theclass_students_idsOne2many). - Add a Dynamic
domain: Apply adomainattribute to the Many2one field, leveraging theparentkeyword.
<field name="class_students_ids"> <!-- One2many field on Class model -->
<tree editable="bottom">
<field name="student_id" domain="[('gender', '=', parent.class_gender)]"/>
<!-- 'gender': field in Student model, 'parent.class_gender': field in Class model -->
</tree>
<!-- Other view definitions -->
</field>
- Restart Odoo: Restart your Odoo server.
- Test: Open a “Class” record. Set the “Class Gender” field (e.g., to “Male”). When you try to add a new student, the pop-up selection list for
student_idshould now only display students whosegenderis “Male”.
Explanation:
The domain attribute is a powerful filtering mechanism in Odoo. By using parent.class_gender inside the domain expression, we create a dynamic filter that adapts based on the value in the parent record. This ensures that users can only select relevant records, preventing data entry errors and maintaining data integrity.
3. Passing Values During Record Creation (Default Values for New Records)
Goal: When a new record is created directly from a Many2one field within a One2many (using “Create and Edit”), automatically pre-populate fields in that new record using values from the parent form.
Example: Continuing with the “Class” and “Student” example, if you create a new student directly from the “Add a line” option within a class, you want the new student’s “Gender” field to automatically match the “Class Gender” selected in the parent class.
Steps:
- Locate the Many2one Field: Same as in Use Case 2.
- Add
contextfor Defaults: Add acontextattribute directly to the Many2one field within the One2many.
<field name="class_students_ids">
<tree editable="bottom">
<field name="student_id"
domain="[('gender', '=', parent.class_gender)]"
context="{'default_gender': parent.class_gender}"/>
<!-- 'default_gender': field in new Student record, 'parent.class_gender': field in Class model -->
</tree>
<!-- Other view definitions -->
</field>
- Restart Odoo: Restart your Odoo server.
- Test: Open a “Class” record and set its “Class Gender”. Click “Add a line” in the students One2many, then click “Create and Edit”. A new “Student” form will open, and you’ll see the “Gender” field already pre-filled with the gender from the parent class.
Explanation:
This is a similar concept to Use Case 1, but applied directly to the Many2one field’s context. When “Create and Edit” is triggered, Odoo uses the context defined on that specific field to set default values for the new record being created in the related model.
4. Conditional Visibility of Columns (Invisible Attribute)
Goal: Dynamically show or hide entire columns in a Tree view based on specific conditions, often derived from parent records or the current user’s context. This cleans up the user interface, showing only relevant information when needed.
Example: In a list of “Class Line Items”, you might want to hide the “Teacher” column if no teacher has been assigned to the parent “Class” yet, making the view less cluttered for incomplete records.
Steps:
- Locate the Column Field: Identify the
<field>tag for the column you want to control within the<tree>view definition. - Add the
invisibleAttribute: Use theinvisibleattribute with a domain-like condition that references the parent.
<field name="class_line_ids"> <!-- One2many field on Class model -->
<tree editable="bottom">
<field name="date"/>
<field name="teacher_id" invisible="not parent.teacher_id"/>
<!-- 'teacher_id': column in current (child) view, 'parent.teacher_id': field in parent form -->
</tree>
</field>
- Restart Odoo: Restart your Odoo server.
- Test: Create a “Class” record without assigning a “Teacher”. Observe the “Class Line Items” tree view; the “Teacher” column should be hidden. Now, assign a “Teacher” to the parent “Class” and refresh; the “Teacher” column should now appear.
Explanation:
The invisible attribute dynamically controls the visibility of a field. The condition not parent.teacher_id evaluates to True (making the field invisible) if the teacher_id field in the parent Class record is empty (False). This technique is incredibly versatile for tailoring views to specific data states or user roles.
5. Smart Button Context (Pre-defined Filters)
Goal: Configure a Smart Button to automatically apply a specific filter to the target view when it is clicked. This streamlines navigation and presents users with pre-filtered data, enhancing usability.
Example: On a “Course” form, you might have a Smart Button to view all “Students in Draft Status” for that course. Clicking this button should open the Student list view with the “Draft” filter already applied.
Steps:
- Locate the Smart Button: Find the
<button>element that defines your smart button in the view XML (e.g.,course_views.xml). - Add
contextforsearch_default_*: Include acontextattribute with asearch_default_key.
<button name="%(your_module.action_students)d" type="action"
class="oe_stat_button" icon="fa-users" string="Draft Students"
context="{'search_default_state': 'draft'}">
<field name="student_count" widget="statinfo"/>
</button>
%(your_module.action_students)d: Replace with the XML ID of the action that opens the student list.search_default_state:statemust match thenameof a filter defined in the Student Search View.'draft': The value the filter should match.
- Verify Search Filter: Ensure your target model’s Search View (e.g.,
student_views.xml) has a filter defined with a matchingnameattribute.
<filter string="Draft" name="state" domain="[('state', '=', 'draft')]"/>
- Restart Odoo: Restart your Odoo server.
- Test: Open a “Course” record. Click the “Draft Students” smart button. The student list view should open, and you’ll see the “Draft” filter automatically activated, showing only students in that state.
Explanation:
Odoo’s search_default_ context key is designed specifically for pre-activating search filters. When the action defined by the smart button is executed, it carries this context, and the target search view recognizes it, applying the corresponding filter. This is a common and highly effective pattern for navigating between related records with specific data subsets.
6. Dynamic View Selection (Form View Reference)
Goal: Force Odoo to open a specific form, tree, or kanban view for a related record, overriding the model’s default view, based on the context from where it’s accessed. This provides fine-grained control over the user interface flow.
Example: When creating a new student from within a “Class” form, you might want a simplified “Student Creation” form to open, rather than the full, complex student details form.
Steps:
- Identify Target View: Get the XML ID of the specific form view you want to open (e.g.,
your_module.view_student_form_simplified). - Add
form_view_idto Context: In the One2many field’s context, specify theform_view_id.
<field name="class_students_ids">
<tree editable="bottom">
<field name="student_id"/>
</tree>
<context="{'form_view_id': 'your_module.view_student_form_simplified'}"/>
<!-- 'your_module.view_student_form_simplified': XML ID of the specific student form to open -->
</field>
- Restart Odoo: Restart your Odoo server.
- Test: Open a “Class” record. Click “Add a line” for students, then “Create and Edit”. The simplified student form (if you’ve created one) should now open, instead of the standard student form. The same concept applies to
tree_view_idandkanban_view_idfor list and kanban views, respectively.
Explanation:
Odoo typically opens the default form view for a model. By setting form_view_id (or tree_view_id, kanban_view_id) in the context, you’re explicitly telling Odoo which specific view to render. This is extremely useful when you have multiple forms for the same model, each serving a different purpose or workflow.
7. Context-Based View Customization (Context Get – Advanced Dynamic Fields)
Goal: Implement highly dynamic view behavior where the visibility, editability, or even content of fields and pages changes based on a custom context key passed from the originating action or menu item. This is incredibly powerful for reducing view duplication.
Example: Suppose you have a standard “Student” form, but for a special “Students Without Attendance” menu item, you want to hide the entire “Attendance” page.
Steps:
- Create a Menu Item and Action with Custom Context: Define a new menu item and action. In the action’s
contextattribute, pass a custom key-value pair.
<menuitem id="menu_students_no_attendance"
name="Students without Attendance"
action="your_module.action_students_no_attendance"
parent="your_module.menu_students_root"
sequence="10"/>
<record id="action_students_no_attendance" model="ir.actions.act_window">
<field name="name">Students without Attendance</field>
<field name="res_model">your_module.student</field>
<field name="view_mode">tree,form</field>
<field name="context">{'hide_attendance_page': True}</field>
<!-- Custom context key -->
</record>
- Add a Computed Field (Python): For Odoo’s
attrsto work effectively with context on existing records, it’s often best to create a computed field in your model that reflects the context value.
from odoo import models, fields, api
class Student(models.Model):
_name = 'your_module.student'
_description = 'Student'
# ... existing fields ...
_hide_attendance_page = fields.Boolean(
string="Hide Attendance Page",
compute='_compute_hide_attendance_page'
)
@api.depends_context('hide_attendance_page') # Mark dependency on context key
def _compute_hide_attendance_page(self):
for record in self:
record._hide_attendance_page = self.env.context.get('hide_attendance_page', False)
- Modify the Target View (XML): In the Student Form view, use the
attrsattribute on the target page or field, referencing the computed field.
<page string="Attendance" attrs="{'invisible': [('_hide_attendance_page', '=', True)]}">
<!-- Content of the attendance page -->
</page>
<!-- Or for a specific field -->
<field name="attendance_status" attrs="{'invisible': [('_hide_attendance_page', '=', True)]}"/>
- Restart Odoo: Restart your Odoo server.
- Test: Open the “Student” form from the “Students without Attendance” menu item. The “Attendance” page should be hidden. If you open it from the standard “Students” menu, the page should be visible. This technique can also be used for
readonly,required, etc.
Explanation:
This powerful approach uses context.get() in conjunction with a computed field. The action pushes a custom key (hide_attendance_page) into the context. The computed field _compute_hide_attendance_page then reads this value from self.env.context.get(). Finally, the attrs attribute in the XML view dynamically controls the visibility of the page or field based on the computed field’s value. This allows for incredibly flexible UI adjustments without duplicating views.
8. Conditional Filters in Search Views (Context Get)
Goal: Dynamically control the visibility of filters in a Search View based on the context from which the view is opened. This allows for specialized search experiences without creating multiple search views.
Example: You have a default “Student” search view with a “Draft” filter. For a “Students for Enrollment” menu item, you want to hide the “Draft” filter, as draft students aren’t relevant for enrollment.
Steps:
- Create a Menu Item and Action with Custom Context: Similar to Use Case 7, define an action with a custom context key.
<menuitem id="menu_students_for_enrollment"
name="Students for Enrollment"
action="your_module.action_students_for_enrollment"
parent="your_module.menu_students_root"
sequence="20"/>
<record id="action_students_for_enrollment" model="ir.actions.act_window">
<field name="name">Students for Enrollment</field>
<field name="res_model">your_module.student</field>
<field name="view_mode">tree,form</field>
<field name="context">{'hide_draft_filter': True}</field>
<!-- Another custom context key -->
</record>
- Modify the Search View (XML): In the target Search View (e.g.,
student_search_view.xml), add aninvisibleattribute to the specific filter.
<filter string="Draft" name="draft_students_filter" domain="[('state', '=', 'draft')]"
invisible="context.get('hide_draft_filter')"/>
- Restart Odoo: Restart your Odoo server.
- Test: Open the Student list from the “Students for Enrollment” menu item. The “Draft” filter should be hidden. If you open the Student list from the standard “Students” menu, the “Draft” filter should be visible.
Explanation:
This technique directly uses context.get() within the invisible attribute of a <filter> tag in the search view. When the action is executed, the hide_draft_filter key is present in the context. The search view’s filter then reads this context, and if hide_draft_filter is True, the filter becomes invisible. This provides a clean way to tailor the search experience dynamically.
Advanced Tips and Best Practices for Odoo Context Tutorial
While incredibly powerful, effective use of Odoo context requires some strategic thinking:
- Prioritize Readability: Although context reduces code, overly complex context expressions can be hard to debug. Strive for clarity.
- Use Specific Keys: Avoid generic key names (e.g.,
{'my_flag': True}). Instead, use descriptive names like{'skip_validation': True}or{'force_read_only': True}to make your code more understandable. - Beware of Over-Reliance: For major behavioral changes or completely different layouts, creating separate views might still be a better option for maintainability than extremely complex context-driven logic. Context is best for subtle variations and dynamic adjustments.
- Performance Considerations: While generally efficient, excessively large context dictionaries or overly complex computed fields that depend on context can, in rare cases, have a minor performance impact. Always test your implementations.
- Documentation: If you’re using complex context patterns, document them thoroughly, especially custom context keys and their intended effects. This helps future developers understand your design choices.
- Combine Techniques: As shown in some examples, you can combine
domainandcontextattributes on the same field to achieve sophisticated behaviors.
For further exploration and deeper insights into Odoo development, consider checking out Odoo’s official documentation (https://www.odoo.com/documentation/) or relevant community forums like the Odoo Community Association (OCA). You might also find this internal link useful: Internal Link: Mastering Odoo Views for UI Customization.
Conclusion
This Odoo Context Tutorial has demonstrated how mastering Odoo’s context mechanism can dramatically enhance your development efficiency and the user experience of your Odoo applications. From simply passing default values to dynamically altering view components and filters, context is a versatile tool in the Odoo developer’s arsenal.
By intelligently leveraging context, you can:
- Reduce boilerplate code and simplify view definitions.
- Create highly adaptable and user-friendly interfaces that respond to specific scenarios.
- Streamline workflows by pre-filling data and guiding user interactions.
We encourage you to experiment with these techniques in your own Odoo projects. Should you have any questions, encounter specific scenarios, or wish to share your own context-based solutions, please feel free to leave a comment below. Happy coding!
Discover more from teguhteja.id
Subscribe to get the latest posts sent to your email.

