Odoo External ID / XML ID Helper

Stop guessing XML ID naming conventions — and stop retyping env.ref() by hand.

Suggest a name

Record type
View type
Model name
Detail (optional)
Your module (optional)
Suggested XML ID

sale_order_view_form

Add your module name above to see usage snippets.

Advertisement

The basics

What is an external ID (XML ID)?

An external ID (also called an XML ID) is the stable string Odoo uses to reference a specific record — stored in ir.model.data, looked up via env.ref(), and written as ref="..." in XML data files. It always has the shape module.name, e.g. sale.action_orders — the module prefix is what keeps the same short name from colliding across modules.

sale module
.
action_orders name

Getting started

How to use this tool

Build

Pick a record type and model, and get a name that follows the widely-used community convention — add your module name to see the full id and every way to reference it.

Inspect

Paste an existing external ID from your code to validate its format and instantly get its Python/XML usage snippets.

Reference — not a rule

Naming conventions by record type

Odoo doesn't enforce any of this — ir.model.data accepts any valid identifier as a name. These are the widely-followed OCA/community conventions this tool's Build mode suggests.

View
<model>_view_<type>
sale_order_view_form
Action (window)
<model>_action
sale_order_action
Menu
<model>_menu
sale_order_menu
Security group
group_<name>
group_sale_manager
Record rule
<model>_rule_<detail>
sale_order_rule_personal
Sequence
seq_<name>
seq_sale_order
Scheduled action
ir_cron_<name>
ir_cron_send_reminders
Report
<model>_report_<name>
sale_order_report_saleorder

Examples

Referencing an external ID

Every common place an id shows up in Python and XML.

self.env.ref('sale.action_orders')

Python — the most common form, inside a model method.

env.ref('sale.action_orders').id

Python — the raw database id, when an API needs an integer rather than a recordset.

<field name="res_model_id" ref="sale.action_orders"/>

XML — a many2one field pointing at another record.

<field name="group_ids" eval="[(4, ref('base.group_user'))]"/>

XML — ref() called inside eval, here to add a group to a many2many via Odoo's (4, id) command.

%(base.group_user)d

Old-style % substitution — still parsed by Odoo but considered legacy; prefer eval="ref('...')" in new code.

FAQ

Frequently asked questions

What is an external ID (XML ID) in Odoo?

A stable string identifier for a specific database record — module.name — stored in the ir.model.data table. It's how XML data files, module upgrades, and code reference records that don't have a predictable database id.

Why does an external ID need a module prefix?

Because the same short name (e.g. 'action_orders') is reused across many modules — the module prefix ('sale.action_orders' vs 'purchase.action_orders') is what keeps them from colliding.

Can the name part contain dots?

Yes — Odoo splits an external ID on only its first dot, so 'sale.my.nested.id' is module 'sale' and name 'my.nested.id'. In practice this is rare; most XML IDs use underscores, not dots, within the name.

What's the difference between ref="..." and eval="ref('...')" in XML?

ref="..." is a shorthand only valid for a field that is itself a relation (many2one, many2many); eval="ref('...')" runs Python inside the field value, so it works anywhere a Python expression is expected — e.g. inside an (4, ref('...')) command for a many2many.

Is the %(module.name)d substitution still used?

It still works, but it is a legacy form from older Odoo versions. Modern code prefers eval="ref('module.name')", which is clearer and works in more contexts.

Do I have to follow the naming conventions this tool suggests?

No — Odoo does not enforce them. They are widely-followed OCA/community conventions that make a module easier for other developers (and future you) to navigate, not a technical requirement.

What happens if two modules define the same external ID?

It's not allowed within the same module, but a different module CAN reference and even override another module's record via its full external id — that's a normal, supported pattern (e.g. overriding a view via inherit_id).

How do I find the XML ID of an existing record?

With developer mode enabled, open the record's form view, then Settings icon (or the debug menu) > 'View Metadata' — it shows the external id directly, or tells you the record has none yet.