Enable Dark Mode!
overview-of-rare-orm-method-nameget-in-odoo-19.jpg
By: Muhammed Fahis V P

Overview of Rare ORM Method name_get() in Odoo 19

Technical Odoo 19 Odoo Enterprises Odoo Community

If you have done any significant amount of Odoo module development, you are well aware of the classic Odoo ORM methods like create(), write(), search(), unlink(). However, there are several additional ORM methods provided by Odoo's ORM that do their job without your attention, and which usually become apparent only when they start failing and you see clients complaining because of an unusual drop-down list or something similar. One such method is name_get().

It allows you to specify how a particular record will be referred to in many contexts, including many2one dropdowns, breadcrumbs, chatter message mentions, and wherever else Odoo needs to represent a record in the user interface with its readable name. However, there is one important thing to note about name_get(): in Odoo 19, the web client uses the display_name field to generate the label, not name_get().

What Does name_get() Actually Do?

Every time Odoo needs to show a linked record as a label  in a Many2one dropdown, a breadcrumb, or a chatter reference, it needs to know what text to display. The method responsible for building that label is name_get().

It runs on a recordset and returns a list of tuples, where each tuple is (record_id, display_name):

# What the return format looks like
[(1, 'Azure Interior'), (2, 'Deco Addict'), (3, 'Agrolait')]

Default Behaviour: What Odoo Does Without Any Override

If you don't write a name_get() method in your model, Odoo falls back to its base implementation in models.BaseModel. It simply reads the field defined in _rec_name (which defaults to name) and returns it.

# This is roughly what the base ORM does internally
def name_get(self):
    result = []
    name_field = self._rec_name or 'name'
    for record in self:
        result.append((record.id, record[name_field] or ''))
    return result

So if your model has a name field and you haven't touched name_get(), the dropdown shows just that value. Clean, but not always enough.

In Odoo 19 display_name Takes Over

In Odoo 17 onwards, and fully in Odoo 19, the web client fetches display_name as a regular field via the fields API; it no longer calls name_get() directly for Many2one dropdowns. This means:

  • A plain name_get() override will not update what users see in a dropdown in Odoo 19
  • You need to define display_name as a computed field with proper @api.depends
  • Keep name_get() alongside it for backward compatibility and for anything that still calls it via RPC (reports, shell scripts, older integrations)

The right pattern in Odoo 19 is this:

display_name = fields.Char(
    compute='_compute_display_name',
    store=False,
)
@api.depends('name', 'code', 'capacity')
def _compute_display_name(self):
    for record in self:
        name = record.name or ''
        if record.code:
            name = f'[{record.code}] {name}'
        if record.capacity:
            name = f'{name} (Cap: {record.capacity})'
        record.display_name = name
# Keep for backward compatibility
def name_get(self):
    return [(record.id, record.display_name) for record in self]

Example - Hospital Ward Dropdown

Let's say you're building a hospital management module. You have wards, and each ward has a name, a code, and a capacity. When a doctor selects a ward on a patient form, seeing just "Cardiology" is not enough if there are multiple Cardiology units across buildings.

Here is the full ward model with the correct Odoo 19 pattern:

from odoo import models, fields, api

class HospitalWard(models.Model):
    _name = 'hospital.ward'
    _description = 'Hospital Ward'
    _rec_name = 'name'
    name = fields.Char(string='Ward Name', required=True)
    code = fields.Char(string='Ward Code')
    capacity = fields.Integer(string='Capacity')
    display_name = fields.Char(
        compute='_compute_display_name',
        store=False,
    )
    @api.depends('name', 'code', 'capacity')
    def _compute_display_name(self):
        for record in self:
            name = record.name or ''
            if record.code:
                name = f'[{record.code}] {name}'
            if record.capacity:
                name = f'{name} (Cap: {record.capacity})'
            record.display_name = name
    def name_get(self):
        return [(record.id, record.display_name) for record in self]

Now, when a doctor clicks the Ward field on a patient form, the dropdown shows:

[W-01] Cardiology (Cap: 20)
[W-02] Neurology (Cap: 15)

instead of just Cardiology and Neurology.

Full Example - Hospital Patient Model

The patient model demonstrates all three concepts together: the computed display_name, name_get() for backward compatibility, and context-based label switching:

[W-01] Cardiology (Cap: 20)
[W-02] Neurology (Cap: 15)

The breadcrumb when you open a saved patient record shows the full label from display_name  [PAT-0042] John Smith (Ward 3). That is name_get() and display_name working together.

Combining name_get() with name_search()

name_get() controls what the label looks like. name_search() controls what users can search by in a Many2one field. They are always a pair.

If your label shows [PAT-001] John Smith but search only checks the name field, a user typing PAT-001 in the dropdown won't find the record. Always override both:

@api.model
def name_search(self, name='', domain=None, operator='ilike', limit=100):
    domain = domain or []
    if name:
        records = self.search(
            ['|',
             ('patient_code', operator, name),
             ('name', operator, name)] + domain,
            limit=limit
        )
        return records.name_get()
    return super().name_search(
        name=name, domain=domain, operator=operator, limit=limit
    )

In Odoo 19 the parameter is domain, not args. Using args will throw a TypeError.

name_get() has been the standard way to customize record labels in Odoo for years, and it still matters, but Odoo 19 shifts the primary responsibility to the display_name computed field for what users actually see in the UI. The right approach now is to define display_name with @api.depends so labels update reactively, keep name_get() alongside it for compatibility, and always pair with name_search() so search and display stay in sync. These small changes make a big difference to how polished and usable your custom modules feel.

To read more about What is Rare ORM Method check_access() in Odoo 19, refer to our blog What is Rare ORM Method check_access() in Odoo 19.


Frequently Asked Questions

Does name_get() still need implementing in Odoo 19?

Yes, although its behavior has changed. The web client directly accesses display_name to build its dropdown menu. name_get() is still required for report generation, shell scripts, old RPC code, and other legacy codebases using the older API interface. Your safest bet is to implement both: a display_name computed field and name_get() method that simply calls display_name.

Why didn't my overridden name_get() affect the Many2one dropdown?

Because the Odoo 19 web client retrieves the display_name field directly rather than calling name_get(). Simply create a display_name field as a computed value, and the dropdown will instantly reflect the change.

What has changed in name_search() in Odoo 19?

The function now expects the name_search() args parameter to be named domain; otherwise, your code will raise TypeError when calling super() with args= in Odoo 19. Make sure you always use the domain when overriding name_search().

How does _rec_name differ from display_name?

_rec_name is just a name of the field that Odoo uses to generate single-field default labels; whereas display_name is an actual computed label, which may include several fields formatted as you wish. In Odoo 19, it is used by the web client.

If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message