Odoo's ORM (Object-Relational Mapping) handles everything between Python code and the database. You create fields, define calculations, and Odoo handles the rest. Computed fields and onchange methods are two of the most commonly used tools.
Computed fields
A field whose value is calculated automatically. Total amount = quantity * unit price. In Python: total = fields.Float(compute='_compute_total'). The method _compute_total runs every time dependent fields change.
Use @api.depends('quantity', 'unit_price') to specify which fields trigger recalculation. Odoo optimizes: the calculation only runs when a dependent field actually changes, not on every read.
Stored computed fields
Add store=True and the value is saved in the database. Advantage: you can search, filter, and group on it. Disadvantage: it takes space and requires recalculation on change. Use it for fields needed in reports and lists. Non-stored for fields only displayed in form view.
Onchange
@api.onchange('partner_id') triggers in real time when the user changes the field in the form. Good for pre-filling related fields: select customer, automatically fill in address and payment terms. Onchange runs in the browser (client-side) before the record is saved.
The difference
Computed fields are calculated on read (or on dependency change if stored). Onchange triggers on interaction in the form. Computed fields work everywhere (API, import, automation). Onchange only works in form view.
Common mistakes
Forgetting @api.depends on computed fields (value never recalculates). Using onchange for business logic that should be a constraint or computed field. Dependency chains: A depends on B which depends on C; don't forget to declare the entire chain.