package_m2o
The many2one that Inventory uses for packages. package_m2o looks like a plain relation field until you notice the names it displays change with the transfer's state and context.
| Technical name | package_m2o |
|---|---|
| Field types | many2one |
| Views | form, list |
| Module | stock (Inventory app) |
| Used in core | 12 occurrences across 2 modules: stock and stock_picking_batch |
| Versions | Odoo 20.0, Odoo 19.0 |
| No-code setup | No. It ships preconfigured on Inventory views; applying it elsewhere is an XML change. |
| Alternatives | many2one, res_partner_many2one, many2one_uom |
What the Package field does
What this means for your team
Supported options in Odoo 19
| Option | Type | What it does |
|---|---|---|
no_open | boolean | Inherited from many2one: suppresses the internal link so clicking never navigates to the package form. Common on operational screens where opening records mid picking is a distraction. |
no_create | boolean | Inherited: removes every creation path from the autocomplete, for operations where packages must pre-exist. |
no_quick_create | boolean | Inherited: removes inline creation from typed text while keeping the dialog path, which here is the save and reload dialog described above. |
no_create_edit | boolean | Inherited: removes the Create and Edit dialog entry while keeping quick create. |
search_threshold | number | Inherited: minimum typed characters before the search fires, instead of searching on focus. Useful on databases with tens of thousands of packages. |
placeholder_field | field name | Inherited: a char field on the record supplying a dynamic placeholder for the empty state. |
can_scan_barcode | boolean | Inherited and undocumented: read by the base extractProps without appearing in the declared options, it flags the field as barcode scannable for Odoo's scanning flows. |
create_name_field | field name | Inherited and undocumented: which field on stock.quant.package receives typed text on quick create. Rarely useful for sequence named packages, but it is read by the shared extract.(default: name) |
The package behavior is driven by context, not options. The view passes context="{'show_src_package': True}" or show_dest_package on the field, the widget forwards those flags plus the record's done state into the field context, and stock.quant.package's server side display name computation reads them: source flag renders the package's full chain, destination flag the destination chain, done state the bare name. Options in the table below tune the many2one behavior itself.
Working examples
Context flags, done state and the Unnamed fix
Version compatibility
| Version | Status | Notes |
|---|---|---|
| Odoo 20.0 | In development | Not released. Internal refactor only on the development branch; behavior unchanged. Details below. |
| Odoo 19.0 | Verified | Verified against the shipped source. First version where the widget exists. |
| Odoo 18.0 | Not available | Widget absent from the 18.0 tree. Package columns render as plain many2one fields. |
Upgrade note. This widget does not exist in Odoo 18: the file and registration appear in 19.0, where package columns previously rendered as plain many2one fields. Custom 18 views cannot reference it, and after migrating to 19 the specialized rendering arrives by simply using the core views, or adding the widget to custom ones.
What is changing in Odoo 20
Common problems and fixes
| Symptom | Cause and fix |
|---|---|
| Package shows its full chain where you expected the short name | The field's context carries show_src_package or show_dest_package, and the record is not done. Drop the context flag on that view if the chain is unwanted. |
| Package names suddenly shortened after validating a transfer | Done and canceled records collapse to the last name segment, server and client side. Expected. Open the package record itself to see its position in the hierarchy. |
| New package briefly named Unnamed in a custom flow | A custom creation path bypasses the widget's save and reload dialog, so the sequence name has not been fetched. Create through the field's own dialog, or reload the record after creation in your flow. |
| The widget errors outside Inventory models | It is built for stock.quant.package relations and its display logic assumes that model's context contract. Use a plain many2one for other relations. |
| View referencing package_m2o fails on Odoo 18 | The widget only exists from 19.0. Drop the widget attribute on 18, or upgrade; the field works as a standard many2one meanwhile. |
| Users create junk packages from the dropdown | Quick create is open by default, as on any many2one. Add no_create, or no_quick_create to force the dialog path. |
Package field vs the alternatives
| Widget | Best for | Key difference |
|---|---|---|
package_m2o | Package fields on move lines and batch transfers | Context aware hierarchy names plus the create and reload fix |
many2one | Any other relation on custom warehouse views | No package context contract, plain display names |
| res_partner_many2one | Partner fields with company autocomplete | Same pattern of a specialized many2one, tuned for partners instead |
| many2one_uom | Unit of measure fields next to quantities | Another specialized many2one, packaged with quantity awareness |
Frequently asked questions
What is the package_m2o widget in Odoo?+
Why does the same package display differently on different screens?+
Does package_m2o support the normal many2one options?+
Why did my new package show as Unnamed in a custom screen?+
Can I use package_m2o in Odoo 18?+
Can I use package_m2o on my own model?+
Does package_m2o change in Odoo 20?+
Warehouse screens slowing the floor down?
Package hierarchies, batch pickings and barcode flows only feel effortless when the views are tuned to how your floor actually moves stock. We build and refine Odoo Inventory operations, custom move line views, scanning flows, package logic, keeping core widgets and upgrade paths intact.
Book a free consultation