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:
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"
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