Chapter 4 - Odoo 15 Development Book

Creating Records

create() function is used to create new records for a particular model. The new records are initialized using the values from the list of dicts vals_list, and, if necessary, those from the default_get() function.

Parameters

Values for the model’s fields, as a list of dictionaries:

[{'field_name': field_value, ...}, ...]

Eg:

partner = self.env['res.partner'].create({
     'name':'Test Partner',
     'is_company':True
})

It will raise an AccessError

  • If the user has no create access on the requested object
  • If the user tries to bypass access rules for creat on the requested object

It will raise ValidationError

  • If the user tries to enter an invalid value for a field that is not in selection

It will raise UserError

  • If a loop would be created in a hierarchy of objects a result of the operation (such as setting an object as its own parent)

Updating Records

Sometimes it’ll be required to update records by changing the values of some of their fields.

We can use the update() method of a model for this.

There are three ways to assign a particular field value to a record.

1. Assigning values directly to the attribute representing the field of the record.

- We can assign a value to a field directly.

self.test_boolean = True

self is the object of the record of which record’s field value is updating.test_boolean is a boolean field.

2.update() method

- We can use the update() method to update the value of a field.

self.update({
   'start_date': fields.Date.today(),
   'test_boolean': True
}) 

start date and test_boolean is the field which we need to update. We can pass a dictionary that maps the field names to the values you want to set to the update method.

3.write() method

- We can pass a dictionary that maps the field names to the values you want to set to the update method

self.write({
   'start_date': fields.Date.today(),
   'test_boolean': True
}) 

- This method works for recordsets of arbitrary size and will update all records with the specified values in one single database operation when the two previous options perform one database call per record and per field. However, it has some limitations: it does not work if the records are not yet present in the database. Also, it requires a special format when writing relational fields, similar to the one used by the create() method.

(0, 0, { values }) link to a new record that needs to be created with the given values dictionary.

(1, ID, { values }) update the linked record with id = ID (write values on it).

(2, ID) remove and delete the linked record with id = ID (calls unlink on ID, that will delete the object completely and the link to it as well).

(3, ID) cut the link to the linked record with id = ID (delete the relationship between the two objects but do not delete the target object itself).

(4, ID) link to existing record with id = ID (adds a relationship).

(5) unlink all (like using (3, ID) for all linked records).

(6, 0, [IDs]) replace the list of linked IDs (like using (5) then (4, ID) for each ID in the list of IDs).

Searching Records

Searching records based on some conditions are necessary for business logic methods. In Odoo, we can use search() method to do so.

Let’s take an example; in this example, we are searching those partners whose ‘company_type’ is ‘company’

domain = [('company_type','=','company')]
partner = self.env['res.partner'].search(domain)
>>>res.partner(1,2,3,6,9,10,13,15,16,17)

The search method with the domain will return the recordest. A domain is a list of criteria, each criterion being a triple (either a list or a tuple) of (field_name, operator, value).

    ● field_name (str)

    A field name of the current model, or a relationship traversal through a Many2one using dot-notation, e.g. 'street' or 'partner_id.country'

    ● operator (str)

    an operator used to compare the field_name with the value. Valid operators are:

    = equals to

    !=not equals to

    >greater than

    >=greater than or equal to

    < less than

    <= less than or equal to

    =? unset or equals to (returns true if value is either None or False, otherwise behaves like =)

    =like - matches field_name against the value pattern. An underscore _ in the pattern stands for (matches) any single character; a percent sign % matches any string of zero or more characters.

    like - matches field_name against the %value% pattern. Similar to =like but wraps value with ‘%’ before matching.

    not like - it doesn’t match against the %value% pattern.

    ilike - case insensitive like.

    not ilike - case insensitive not like.

    =ilike - case insensitive =like.

    not in-is unequal to all of the items from value.

    child_of-Is a child (descendant) of a value record (value can be either one item or a list of items).

    Takes the semantics of the model into account (i.e., following the relationship field named by _parent_name).

    parent_of - Is a parent (ascendant) of a value record (value can be either one item or a list of items).

    Takes the semantics of the model into account (i.e., following the relationship field named by _parent_name).

    value

    Variable type must be comparable to the named field with the operator.

Domain criteria can be combined using logical operators in prefix form:

'&' - logical AND

'|'- logical OR

'!'- logical NOT

Note:

Mostly to negate combinations of criteria. Individual criterion generally have a negative form (e.g., = -> !=, < -> >=) which is simpler than negating the positive.

Example:

To search for partners named ABC, from Belgium or Germany, whose language is not English:

[('name','=','ABC'),
 ('language.code','!=','en_US'),
 '|',('country_id.code','=','be'),
     ('country_id.code','=','de')]

This domain is interpreted as:

(name is 'ABC')
AND (language is NOT english)
AND (country is Belgium OR Germany)

The other keyword arguments that matches in the search method.

•offset=N: This is used to skip the first N records that match the query. Its default is 0.

• limit=N: This indicates that N records will be returned. By default, there is no limit.

• order=sort_specification: By default, the order is the _order attribute of the model class.

• count=boolean : If True, it will return the number of records in the recordset.The default is False

Note:

The search() method with the count attribute and search_count() function both gives the same result.

Combining Recordset

Sometimes, we will get a recordset that is not what we need.

1. To merge two recordsets into one while preserving their order:result = recordset1 + recordset2

2. To merge two recordsets into one by ensuring that there are no duplicates in the result:result = recordset1 | recordset

3. To find the records that are common in two recordsets: result = recordset1 & recordset2.

Some of the common python operators that can be used in combining recordsets:

    -R1+R2: This will return a combination of the two recordsets, the records from R1 followed by the records from R2. The new recordset may have duplicate records

    -R1-R2: This will return a new recordset that will have records from R1 that are not in R2. The order is preserved.

    -R1&R2: This will perform the intersection of the two recordsets. It will contain the records from both R1 and R2 but no duplicates. The order is not preserved.

    -R1 | R2: This will perform the union of the two recordsets. This will return a new recordset with records from either R1 or R2. There are no duplicate records. The order is not preserved.

    -R1==R2: It will return True if both the recordsets R1 and R2 have the same records.

    -R1<=R2: True if all records in R1 are a subset of R2.

    -R1< R2: True if all records in R1 are a subset of R2.

    -R1>=R2: True if all the records in R2 are a subset of R1.

    -R1 !=R2: True if both the recordset have no same records.

    -R1 in R2: True if R2 contains R1.R1 should be one record

    -R1 not in R2: True if R2 doesn’t contain R1.R1 should be one record.

Filtering Records

Sometimes, if we already have a recordset and need a subset of the recordset based on some conditions, we will filter out the corresponding records from the recordset, we use filtered() method for this.

A function or a dot-separated sequence of field names can be passed as a parameter to the filtered() function. It will return the records satisfying the condition, which may be empty.

# only keep records whose company is the current user's
records.filtered(lambda r: r.company_id == user.company_id)
# only keep records whose partner is a company
records.filtered("partner_id.is_company")

Sorting Records

The sorted() method can be used to sort a recordset.

  • If the recordset is obtained by a search() method, the order attribute can be used in the method to sort the returned recordset.
  • partner = self.env['res.partner'].search([(),order='id'])

    This will return all the partners which are sorted in ascending order of records ‘id’.

  • _order attribute of the model can also be used to sort the records of the model
  • sorted() method can be used to sort a recordset
  • partners = self.env['res.partner'].search([('company_type','=','company')])
    partners.sorted(key='id')

    Internally, the sorted() method will fetch the data of the field that's passed as the key argument. Then, by using Python's native sorted method, it returns a sorted recordset.

    It also has one optional argument, reverse=True , which returns a recordset in reverse order.

    partners = self.env['res.partner'].search([('company_type','=','company')])
    partners.sorted(key='id', reverse=True)
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