Traversing recordset relations

When working with a recordset of length 1, the various fields are available as record attributes. Relational attributes (One2many, Many2one, and Many2many) are also available with values that are recordsets too. When working with recordsets with more than one record, the attributes cannot be used.

This recipe shows how to use the mapped() method to traverse recordset relations; we will write two methods performing the following operations:

  • Retrieving the e-mails of all contacts of a single partner company passed as an argument
  • Retrieving the various companies to which some contact partners are related

Getting ready

We will be reusing the simplified Partner model shown in the Create new records recipe of this chapter.

How to do it…

To write the partner manipulation methods, you need to perform the following steps:

  1. Define a method called get_email_addresses():
        @api.model
        def get_email_addresses(self, partner):
            partner.ensure_one()
  2. Call mapped() to get the e-mail addresses of the contacts of the partner:
           return partner.mapped('child_ids.email')
  3. Define a method called get_companies():
        @api.model
        def get_companies(self, partners):
  4. Call mapped() to get the different companies of the partners:
           return partners.mapped('parent_id')

How it works…

In step 1, we call ensure_one() to make sure we have a single partner. This is not required for the recipe, as mapped() works very well on recordsets of arbitrary size. However, it is mandated by the specification of the method we are writing, as we don't want to retrieve contacts from multiple companies by mistake.

In step 2 and step 4, we call the mapped(path) method to traverse the fields of the recordset; path is a string containing field names separated by dots. For each field in the path, mapped() produces a new recordset containing all the records related by this field to all elements in the current recordset and then applies the next element in the path on that new recordset. If the last field in the path is a relational field, mapped() will return a recordset; otherwise, a Python list is returned.

The mapped() method has two remarkable properties:

  • If the path is a single scalar field name, then the returned list is in the same order as the processed recordset.
  • If the path contains a relational field, then order is not preserved, but duplicates are removed from the result.

Note

This second property is very useful in a method decorated with @api.multi where you want to perform an operation on all the records pointed by a Many2many field of all records in self, but need to make sure that the action is performed only once (even if two records of self share the same target record).

There's more…

When using mapped(), keep in mind that it operates in the memory inside the Odoo server by repeatedly traversing relations and therefore making SQL queries, which may not be efficient; however, the code is terse and expressive. If you are trying to optimize a method on the critical path of the performance of your instance, you may want to rewrite the call to mapped() and express it as a search() with the appropriate domain, or even move to SQL (at the cost of readability).

The mapped() method can also be called with a function as argument. In this case, it returns a list containing the result of the function applied to each record of self, or the union of the recordsets returned by the function, if the function returns a recordset.

See also

  • The Search for records recipe
  • The Executing raw SQL queries recipe In Chapter 6, Advanced Server Side Development Techniques
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.161.228