What is difference between @api.one, @api.multi and @api.model?

api.one is meant to be used when method is called only on one record. It makes sure, that there are no multiple records when calling method with api.one decorator. Let say you got record partner = res.partner(1,). It is only one record and there is method for example (in res.partner):

@api.one
def get_name(self):
    return self.name #self here means one record

calling it like this works:

partner.get_name()

But if there would be more records, like partners = res.partner(1, 2,)

calling it, would raise a Warning, telling you that you can only call it on one record. For multiple records api.multi is used, where self is recordset and it can be iterated through all records to do something. For example:

@api.multi
def get_partner_names(self):
    names = []
    for rec in self:
        names.append(rec.name)
    return ', '.join(names)

And api.model is considered to be used when you need to do something with model itself and don't need to modify/check some exact model's record/records. For example there could be method that returns some meta info about model's structure or some helper methods, etc. Also in documentation it is said that this api is good to use when migrating from old api, because it "politely" converts code to new api. Also in my own experience, if you need method to return something, model decorator is good for it. api.one returns empty list, so it might lead to unexpected behavior when using api.one on method when it is supposed to return something.

Some more info: http://odoo-new-api-guide-line.readthedocs.org/en/latest/decorator.html


api.one

This decorator loops automatically on Records of RecordSet for you. Self is redefined as current record:

@api.one   ## here you will get singleton object in self
def name(self):
    self.name = ’admin’

@api.multi

Self will be the current RecordSet without iteration. It is the default behavior:

@api.multi  ## here you will get multi objects in self
def name(self):
    print len(self)
    for obj in self:
        obj.name = 'Admin'

@api.model

This decorator will convert old API calls to decorated function to new API signature. It allows to be polite when migrating code.

@api.model 
def name(self):
    pass

Method decorators needs to be defined according to your methods need, if you want to return dictionary from the method then your method must contains @api.multi.

Refer New API Guideline


  • Difference between one, multi and model

You actually can call an @api.one method with a RecordSet containing multiple records. The only difference is that with @api.one the looping on records will be done outside of the function that you define, and as self the decorator will pass each record in the RecordSet one by one.

As an example, let's define two functions in our model example.model:

@api.one
def print_self_one(self):
    print self

@api.multi
def print_self_multi(self):
    print self

And let's call them both the following way from odoo shell:

model = env['example.model']
record_set = model.browse(1,2)
print "record set: " + record_set
print "using @api.one:"
record_set.print_self_one()
print "using @api.multi:"
record_set.print_self_multi()

Would return:

record set: example.model(1,2)
using @api.one:
example.model(1)
example.model(2)
using @api.multi:
example.model(1,2)

Thus, the following two are equivalent:

@api.one
_compute_name(self):
    self.name = "Default Name"

@api.multi
print_self_multi(self):
    for record in self:
        record.name = "Default Name"

even if thery are called with more record in the recordset.

On the other hand, you do not use any decorator, then it can not be called with more (or less) than one record, or it will complain and probably stop with an error.

@api.model is a completely different story: you should only use this decorator if you only expect it to be called with an empty recordset.

  • When to use which

If you expect a non-empty RecordSet as input value, then, in many cases, you can use both @api.one and @api.multi, it is just a matter of personal preference. I personally prefer to use @api.one when it is possible, because I find the code much cleaner that way (also, for compute and onchange methods the Odoo source generally uses @api.one).

There are a few cases where you can only use @api.multi though:

  1. If you not only want to loop on the records, but you would also want to do something only once:

     @api.multi
     print_self_multi(self):
         print "this will only be  printed once"
         for record in self:
             print "this will be printed len(record_set) times"
    
  2. If return value is important. A function decorated with @api.one will always return a list (a list of the return values in your function as iterations). In a number of cases though, especially when interacting with the GUI, you will have to return a dictionary (for example with a warning). In those cases, you will have to go with @api.multi.


@api.multi

Decorate a record-style method where self is a recordset. The methodtypically defines an operation on records. Such a method::

@api.multi
def method(self, args):
  ...

may be called in both record and traditional styles, like::

recs = model.browse(cr, uid, ids, context)
recs.method(args)

model.method(cr, uid, ids, args, context=context)

@api.model

Decorate a record-style method where self is a recordset, but its contents is not relevant, only the model is. Such a method::

@api.model
def method(self, args):
...

may be called in both record and traditional styles, like::

recs = model.browse(cr, uid, ids, context)
recs.method(args)

model.method(cr, uid, args, context=context)

You can find the base code for these decorators in the file: odoo/api.py

Tags:

Odoo

Odoo 8