Skip to main content
iVentureTeam

many2one_reference

The many2one_reference widget renders a reference field, where the target model lives in a second field, as an ordinary many2one picker. Leave that second field out of the view and it does not degrade: it throws.

September 18, 2026Updated September 18, 20264 min read
Technical namemany2one_reference
Field typesmany2one_reference
Viewsform, list
Moduleweb, present in every Odoo database
Used in core1 explicit use in Odoo 19, in the data_cleaning Enterprise module. It also renders on every many2one_reference field with no widget attribute, through the registry type fallback.
VersionsOdoo 19.0, Odoo 20.0
No-code setupNo. There is no Studio entry, and the field type itself is not something Studio creates.
Alternativesreference, many2one_reference_integer, many2one

What the many2one_reference widget does

A many2one_reference field stores an integer id whose model is not fixed. The model name lives in a companion field, declared on the Python side as model_field. Together they point at any record in the database.

This widget makes that pair usable. It reads the model name out of the companion field, hands it to the standard Many2One component as the relation, and lets the user search and pick a record exactly as they would on an ordinary many2one.

It declares no options. Its extractProps simply delegates to the shared many2one extractor, so it inherits that widget's prop handling rather than defining its own.

What this means for your team

You meet this on models that attach to anything: an activity, a log entry, an attachment, a data-cleaning record. One record has to reference a sales order today and a contact tomorrow, and a fixed relation cannot express that.

For users the experience should be invisible. They pick a type, then they pick a record. What they must not see is a form that fails to open, which is exactly what happens when the view is built wrong, so the next section is worth reading before you put one of these on a screen.

Working examples

The companion field must be present in the view. It can be invisible, but it must be there:

<field name="res_model" invisible="1"/>
<field name="res_id" widget="many2one_reference"/>

This is the version that breaks the form:

<!-- res_model is not in the view: the widget throws on render -->
<field name="res_id" widget="many2one_reference"/>

On the Python side, the pairing is declared on the field itself:

res_id = fields.Many2oneReference("Record", model_field="res_model")

Why a missing companion field throws instead of degrading

Most Odoo widgets fail softly. This one does not, and the code says so explicitly:

get relation() {
    const modelField = this.props.record.fields[this.props.name].model_field;
    if (!(modelField in this.props.record.data)) {
        throw new Error(`Many2OneReferenceField: model_field must be in view (${modelField})`);
    }
    return this.props.record.data[modelField];
}

The getter runs on every render, so the error surfaces the moment the form paints. The user sees a broken view, not a missing field. The message names the field it wanted, which makes the fix obvious once you find the message, and the place to find it is the browser console.

The same getter drives a quieter behavior worth knowing. The props passed down include:

readonly: this.props.readonly || !relation,

So when the companion field is present but empty, the picker renders readonly rather than throwing. A user who has not yet chosen a model cannot type into the record field at all. That is deliberate, since there is nothing to search yet, but it reads as a disabled field with no explanation. If your form puts the record field above the model field, users will hit it constantly. Put the model field first.

Version compatibility

VersionStatusNotes
Odoo 19.0VerifiedVerified against the shipped 19.0 source.
Odoo 20.0VerifiedVerified against the 20.0 branch. No usage changes.

Unchanged between the two branches we checked.

What is changing in Odoo 20

No change. Diffing the many2one_reference registration between the 19.0 and 20.0 branches shows no options added or removed, no registration changes and the same supported type.

The component is rewritten internally for OWL 3, as every widget in Odoo 20 is, but nothing about how you use it from a view changes.

Common problems and fixes

SymptomCause and fix
The form does not render and the console shows 'model_field must be in view'The companion model field named by the field's model_field is not present in the view. Add it to the view. It can carry invisible="1", it only has to be loaded.
The record picker is greyed out and will not accept inputNo model has been chosen yet, so the widget forces readonly because there is nothing to search. Choose the model first. Put the model field above the record field in the layout so the order is obvious.
The picker searches the wrong modelThe companion field holds a different model name than expected, often from a default or an onchange. Inspect the companion field's value on the record. The widget uses it verbatim as the relation.

Many2one_reference widget vs the alternatives

WidgetBest forKey difference
many2one_referenceA reference whose target model varies per recordReal many2one picker, but requires a companion model field in the view
referenceAn occasional pointer with no companion fieldModel and id stored together as text, so harder to query
many2one_reference_integerShowing the raw id rather than the record nameSame field type, but renders the integer and never resolves the name
many2oneA relation to one fixed modelModel is set in the field definition, not at runtime

Compare this with the reference field type, which packs the model and the id into one string column. A reference field is simpler to put on a view because there is no companion field to remember, and worse to query, because the value is text rather than a real integer id. Use many2one_reference when you need to index or join on the id, and reference when you just need to point at something occasionally.

Frequently asked questions

Why does my Odoo form break with 'model_field must be in view'?+
The many2one_reference widget reads the target model from a companion field, and that field is not loaded in the view. Add it to the view, with invisible="1" if users should not see it. The widget throws rather than degrading.
Why is my many2one_reference field readonly?+
Because no model has been selected yet. The widget sets readonly when the companion model field is empty, since there is no relation to search. Choosing the model enables the picker.
Does many2one_reference have any options?+
No. It declares no supportedOptions and delegates prop extraction to the standard many2one widget, so it inherits that behavior instead of defining its own.
What is the difference between many2one_reference and a reference field?+
A many2one_reference stores a real integer id with the model in a separate field, so it can be indexed and joined. A reference field packs model and id into one text column, which is easier to place in a view and harder to query.

Polymorphic links that break your forms?

Reference fields are where generic Odoo models get their flexibility, and where views quietly start throwing. We design the model and the view together so a record can point at anything without anyone seeing a blank screen.

Talk to an Odoo consultant

How this page was produced

Verified by reading addons/web/static/src/views/fields/many2one_reference/many2one_reference_field.js on the 19.0 branch of a local clone of the official Odoo repository. The thrown error and the readonly rule are quoted verbatim from the relation getter and the m2oProps getter. The registration was diffed against the 20.0 branch. Usage counts come from scanning every XML file in Community, Enterprise and odoo/addons/base, which found a single explicit use in data_cleaning. Corrections welcome via our contact page.