Skip to Content

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.
August 13, 2026 by
Martin Schmid
Odoo Administration ORM Database

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.

M
Martin Schmid
2026-08-13

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.

Archive
Why Odoo Does Not Display Visitor Country and How to Fix It
An incorrectly formatted installed GeoIP package can completely halt country statistics. Learn how the error occurs, how to pinpoint it in four steps, and where the database originates.