Why Odoo Customizations via API are Faster than via SQL
Rights, properties, and translations can be changed via the Odoo Shell in just a few lines. A SQL statement often requires several preliminary queries for this.
Grant permissions without touching the database
In support, someone needs administrator rights, and that immediately. The shortest path seems to go through the database: an UPDATE on the rights table, done. Through the Odoo shell it's two lines, and all checks run.
user = env['res.users'].search([('login', '=', 'benutzer@example.com')])
user.write({'group_ids': [Command.link(env.ref('base.group_system').id)]})
env.cr.commit()
The shell is included in every installation. A call with odoo-bin shell -d <datenbank> starts it, without a web server starting up or the production operation noticing.
What write and commit actually do
write() is the regular write path of the data model. It checks required fields and value ranges, recalculates stored computed fields, respects access rules, and records who changed the record. An UPDATE bypasses all that and only writes the value.
env.cr.commit() confirms the transaction. The shell otherwise discards any changes on exit, which regularly costs beginners their work.
The rule behind it is simple. What can be achieved more easily via the API is not done by hand via SQL.
With properties, SQL first collects data
The gap between the two paths grows as soon as the data is nested. Odoo stores properties as JSON, and the value alone sits on the record. The associated definition with type and default value resides on the parent record, e.g., the project for the task.
If you want to change this via SQL, you first identify the parent record, read the definition from a JSON field, locate the internal key of the desired property, and construct the JSON operation for the actual record. Four steps before the statement is even complete. A write() on the field accomplishes the same task in a single line because Odoo combines the definition and value itself.
Translations have been in JSON since Odoo 16
Odoo also stores translatable fields as JSON, with one entry per language in the same column. The previous translation table no longer exists.
Editing JSON via SQL means modifying it exactly in the right place without damaging other languages. Via the API, a language change in the context is sufficient:
product = env['product.template'].browse(42)
product.with_context(lang='de_DE').write({'name': 'Office Chair'})
env.cr.commit()
The English text remains untouched because Odoo addresses the appropriate entry itself.
When SQL is still the right tool
Two cases remain. If the data model doesn't load at all due to stuck modules, the shell won't start either, and a SQL intervention is the only way back. For mass changes involving hundreds of thousands of rows, the detour via the ORM costs more time than the checks are worth. Then, recalculation of the affected computed fields must follow.
For everything in between, the shell is the shorter path. The call takes seconds, and the first query already reveals whether the search expression matches what it should. Odoo Command Line Documentation describes the remaining parameters.