many2many
The default face of a many2many field is an embedded table of linked records with an Add line that opens a selection dialog. Less known: writing widget="many2many" on a one2many field flips it into link and unlink mode, a trick Odoo core itself uses.
| Studio name | Many2Many (default display of the field type) |
|---|---|
| Technical name | many2many |
| Field types | many2many, one2many |
| Views | form (embedded list or kanban), list (as plain text via list.many2many) |
| Also registered as | list.many2many (renders the count as plain text in list cells) |
| Module | web, present in every Odoo database |
| Used in core | 4 explicit occurrences across 4 modules, including l10n_id_efaktur_coretax, gamification, stock_picking_batch; implicitly used by every many2many field without a widget |
| Versions | Odoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0 |
| No-code setup | Yes. Studio applies it automatically when you add a Many2Many field. |
| Alternatives | many2many_tags, many2many_checkboxes, one2many, many2many_binary |
What the Many2many table widget does
What this means for your team
Setting it up in Odoo Studio (no code)
What Studio cannot do here
Supported options in Odoo 19
| Option | Type | What it does |
|---|---|---|
create | boolean or domain | Allows creating new target records from the widget. A domain is evaluated against the parent record. For the Add button in many2many mode it is only the fallback: link wins when present. Becomes an XML attribute on the Odoo 20 development branch.(default: true) |
link | boolean or domain | Governs the Add button in many2many mode (takes precedence over create). A domain is evaluated against the parent record, enabling rules like linking only while draft. Becomes an XML attribute on the Odoo 20 development branch.(default: true) |
unlink | boolean or domain | Controls the per row remove action in many2many mode, which drops the relation without deleting the record. Becomes an XML attribute on the Odoo 20 development branch.(default: true) |
delete | boolean or domain | Controls actual record deletion, relevant in one2many mode; in many2many mode removal goes through unlink instead. Becomes an XML attribute on the Odoo 20 development branch.(default: true) |
write | boolean or domain | New in 19: gates inline editing of embedded rows. When false or when its domain fails, the renderer flips readonly even if the subview is editable. Becomes an XML attribute on the Odoo 20 development branch.(default: true)(since Odoo 19.0) |
Two traps from the source: the edit key is overwritten internally with the record's edition state, so passing it has no effect, and m2o style options like no_create are never read by this widget. On the Odoo 20 development branch all five keys move from options="{...}" to plain XML attributes.
Working examples
Dialog domains, the write gate and the list cell variant
Version compatibility
| Version | Status | Notes |
|---|---|---|
| Odoo 20.0 | In development | Not released. The crud options move from options to XML attributes in the development branch; see below. |
| Odoo 19.0 | Verified | Verified against the shipped source and tested on a clean database; write gating is new here. |
| Odoo 18.0 | Verified | Same component and options except the write gate, which does not exist yet. |
| Odoo 17.0 | Verified | Same registration and crud option handling. |
| Odoo 16.0 | Verified | Same registration; domain capable crud options already supported. |
Views migrate cleanly from 16 through 19. Note that options="{'write': ...}" only has an effect from 19 onward; on 18 and earlier the inline rows follow the subview's own editability alone.
What is changing in Odoo 20
Common problems and fixes
| Symptom | Cause and fix |
|---|---|
| A many2many column in a list view shows 3 records instead of tags | List cells are served by the list.many2many variant, which prints a plain text count and loads no subview. Set widget="many2many_tags" on the field in the list view. |
| Removing a line deleted the record (or did not, when you expected deletion) | many2many mode always unlinks; deletion semantics belong to one2many mode. Check the field type and widget name; use widget="many2many" on a one2many to get unlink behavior on purpose. |
| options="{'edit': False}" has no effect | The component overwrites the edit key internally with the record's edition state. Use the write option (19+) or make the subview non editable in its arch. |
| Users can still create records although create is false | In many2many mode the Add button follows link, not create; the dialog's Create button is what create removes. Set both: options="{'link': ..., 'create': False}". |
| no_create or no_quick_create is ignored | Those are many2one options; this widget never reads them. Use the five crud keys (create, delete, link, unlink, write) instead. |
Many2many table widget vs the alternatives
| Widget | Best for | Key difference |
|---|---|---|
many2many | Managing linked records in a full embedded list or kanban | Complete subview with pager and selection dialog; removal unlinks rather than deletes |
| many2many_tags | Compact tag display and quick picking | Colored pills in one line instead of an embedded table |
| many2many_checkboxes | Small fixed sets picked by ticking | Renders every candidate as a checkbox, capped at 100 records |
| one2many | Child records owned by the parent | Same component in ownership mode: rows are created and deleted, not linked |
| many2many_binary | Attachment collections | Specialized for ir.attachment with an upload button |
Frequently asked questions
What is the many2many widget in Odoo?+
Can I put widget="many2many" on a one2many field?+
How do I stop users adding or removing lines conditionally?+
Why does the Add dialog not show some records?+
What changes for this widget in Odoo 20?+
Relational screens your operators can trust
Wrong unlink versus delete semantics silently destroy data, and the Odoo 20 attribute change will touch every custom x2many view you own. We audit relational views, encode the rules as domains, and prepare your XML for the next migration.
Audit my x2many views