Overview
The Odoo 16 to 17 migration is one of the most technically demanding upgrades in Odoo's history, primarily due to the removal of the attrs attribute from XML views. This guide covers every breaking change with examples and migration patterns.
attrs Removal — Complete Guide
The attrs attribute was the standard way to define conditional visibility, read-only behavior, and required fields in Odoo views for over a decade. In v17, it was replaced with direct attributes using Python-like expressions.
Basic Patterns
# invisible:
# v16: attrs="{'invisible': [('state', '=', 'done')]}"
# v17: invisible="state == 'done'"
# readonly:
# v16: attrs="{'readonly': [('state', '!=', 'draft')]}"
# v17: readonly="state != 'draft'"
# required:
# v16: attrs="{'required': [('type', '=', 'product')]}"
# v17: required="type == 'product'"Complex Domain Patterns
# AND conditions:
# v16: attrs="{'invisible': [('state','=','done'),('type','=','service')]}"
# v17: invisible="state == 'done' and type == 'service'"
# OR conditions:
# v16: attrs="{'invisible': ['|',('state','=','done'),('state','=','cancel')]}"
# v17: invisible="state == 'done' or state == 'cancel'"
# NOT conditions:
# v16: attrs="{'invisible': [('active','=',False)]}"
# v17: invisible="not active"
# 'in' operator:
# v16: attrs="{'invisible': [('state','in',['done','cancel'])]}"
# v17: invisible="state in ('done', 'cancel')"
# Combined attrs:
# v16: attrs="{'invisible': [('state','=','done')], 'readonly': [('state','!=','draft')]}"
# v17: invisible="state == 'done'" readonly="state != 'draft'"Notebook Pages and Groups
# Notebook pages:
# v16: <page string="Details" attrs="{'invisible': [('state','=','draft')]}">
# v17: <page string="Details" invisible="state == 'draft'">
# Groups:
# v16: <group attrs="{'invisible': [('has_partner','=',False)]}">
# v17: <group invisible="not has_partner">OWL 2.x Migration
Custom JavaScript components built on the legacy widget system or OWL 1.x need migration to OWL 2.x patterns:
- Template syntax changes (t-on-click vs onClick)
- Component lifecycle method updates
- Service injection patterns changed
- Registry-based component registration
View Type Considerations
While the tree-to-list rename happened in v18, v17 introduced preparatory changes to view type handling. Custom view types and JavaScript view extensions should be reviewed.
Migration Strategy
- Run a search for
attrs=across all custom module XML files - Convert each occurrence using the patterns above
- Test every form view with various record states
- Review OWL component compatibility
- Run the full test suite
Common Pitfalls
- Forgetting to convert attrs on
<button>elements - Missing attrs on
<page>and<group>elements - Complex nested OR/AND domain conversions
- attrs in
<tree>views (column-level visibility) - Inherited views that override attrs via xpath
DeployMonkey Advantage
DeployMonkey's AI agent understands the attrs-to-expression migration pattern and can validate your custom modules for v17 compatibility. Deploy on Odoo 17+ with confidence that your views are correctly migrated.