How to update Many2many and One2many fields in Odoo

Many2many and One2many fields in Odoo require a specific syntax for manipulating related data. The instructions mainly consist of 3 elements added in a tuple, where each of the elements has a special meaning.

The first element is an integer number ranging from 0 to 6. each corresponding to a different action. The associated actions for each numerical value are:

  • 0: Create
  • 1: Update
  • 2: Delete
  • 3: Unlink
  • 4: Link
  • 5: Clear
  • 6: Set

The second element for Update​, Delete​ and Unlink​ is the ID​ of the record to which the action applies while for the rest of the actions: Create​, Clear​ and Set​ this element is with value 0​.

The third element for the first two actions (Create​ and Update​) is the values​ used to create or update the record. For the next four, this element can be left out. The last action Set​, requires a list of IDs​ as a third element. The IDs​ represent the related records. This command replaces the existing relations with the newly supplied list of records’ IDs​.

In addition, is the complete tuple for each action:

  • Create: (0, 0, values)
  • Update: (1, ID, values)
  • Delete: (2, ID)
  • Unlink: (3, ID)
  • Link: (4, ID)
  • Clear: (5)
  • Set: (6, 0, IDs)

Knowing the logic for the elements in the tuple makes it much easier to understand how to create any action without memorizing the list of tuples. However, from version 15, Odoo made this even easier. Now there is a class helper Command​ that is creating the whole tuple. 

The commands for each action are listed below:

  • Create:  Command.create(values)
  • Update: Command.update(ID, values)
  • Delete:  Command.delete(ID)
  • Unlink: Command.unlink(ID)
  • Link:
  • Clear: Command.clear()
  • Set: Command.set(IDs)

Where values​ represent a dictionary of values, ID​ is an integer value of the record’s id in the database and IDs​ is a list of related records ids in the database.

As an example, we will try to modify the tags related to a sales order. Initially, the sales order has only one tag added to it. That tag is with ID1​.


If the requirement is to add another tag to the sales order which is not presented in the database needs to be used the create​ command:

sale.write({tag_ids: [Command.create({"name": "Tag 2"})]

this will create a new tag and will add it to the order.


In case the name of the newly added tag needs to be updated the update will look like this:

sale.write({tag_ids: [Command.update(2, {"name": "Updated Tag 2"})]      

If the new tag is not needed anymore and needs to be removed from the relation with the sale order but at the same time from the database as well should be used the delete​ command.

sale.write({tag_ids: [Command.delete(2)]

If the requirement was only to remove the tag from the sales order but still to be available in the database then the command unlink​would be the right one.

sale.write({tag_ids: [Command.unlink(2)]        

If the tag with ID 3 that already exists in the database needs to be added to the sale order, then link​ is the correct command to use.

sale.write({tag_ids: []

In case the tags are not needed in the order and need to be removed from it, instead of going over the whole list and using unlink​ it can be done at once with the clear​ command.

sale.clear({tag_ids: [Command.clear()]

The last case is when the current tags, with ID1​ and 3​, which are already added to the order need to be replaced with tags, with ID4​ and 5​, which are in the database but not related to the order.

sale.write({tag_ids: [Command.set([4, 5])]

The end result after this command will be sales order with tags with IDs4​ and 5​.