我对Odoo中的@api.one
,@api.multi
和@api.model
感到困惑。
三者之间有什么区别?他们的用例是什么?
答案 0 :(得分:5)
api.one
。它确保在使用api.one
装饰器调用方法时没有多个记录。假设你有记录partner = res.partner(1,)
。它只有一个记录,并且有方法(例如res.partner
):
@api.one
def get_name(self):
return self.name #self here means one record
这样称之为:
partner.get_name()
但如果会有更多记录,例如partners = res.partner(1, 2,)
调用它,会发出警告,告诉你只能在一条记录上调用它。对于多个记录,使用api.multi
,其中self
是记录集,并且可以通过所有记录迭代来执行某些操作。例如:
@api.multi
def get_partner_names(self):
names = []
for rec in self:
names.append(rec.name)
return ', '.join(names)
当您需要对模型本身执行某些操作并且不需要修改/检查某些确切模型的记录/记录时,会考虑使用api.model
。例如,可能有方法返回一些关于模型结构或一些辅助方法等的元信息。另外在文档中,据说这个api在从旧api迁移时很好用,因为它"礼貌"将代码转换为新的api。另外根据我自己的经验,如果你需要方法来返回一些东西,model
装饰器对它有好处。 api.one
返回空列表,因此当它应该返回某些内容时,在方法上使用api.one
时可能会导致意外行为。
更多信息:http://odoo-new-api-guide-line.readthedocs.org/en/latest/decorator.html
答案 1 :(得分:1)
<强> api.one 强>
这个装饰器会自动在RecordSet记录上循环。 Self被重新定义为当前记录:
@api.one ## here you will get singleton object in self
def name(self):
self.name = ’admin’
<强> @ api.multi 强>
Self将是没有迭代的当前RecordSet。这是默认行为:
@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 强>
此装饰器会将旧的API调用转换为装饰函数,以转换为新的API签名。它允许在迁移代码时保持礼貌。
@api.model
def name(self):
pass
需要根据方法需要定义方法装饰器,如果要从方法返回字典,则方法必须包含@api.multi
。
答案 2 :(得分:1)
您实际上可以使用包含多个记录的RecordSet调用@api.one
方法。唯一的区别是,对于@api.one
,记录的循环将在您定义的函数之外完成,而self
装饰器将逐个传递RecordSet中的每个记录。
例如,让我们在模型example.model
中定义两个函数:
@api.one
print_self_one(self):
print self
@api.multi
print_self_multi(self):
print self
让我们从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()
会回来:
record set: example.model(1,2)
using @api.one:
example.model(1)
example.model(2)
using @api.multi:
example.model(1,2)
因此,以下两个是等价的:
@api.one
_compute_name(self):
self.name = "Default Name"
@api.multi
print_self_multi(self):
for record in self:
record.name = "Default Name"
即使在记录集中有更多记录调用thery。
另一方面,你不使用任何装饰器,然后它不能用一个或多于一个记录来调用,否则它会抱怨并可能因错误而停止。 / p>
@api.model
是一个完全不同的故事:如果您只希望使用空记录集调用它,则应该只使用此装饰器。
如果您希望将非空RecordSet作为输入值,那么在许多情况下,您可以同时使用@api.one
和@api.multi
,这只是个人偏好的问题。我个人更喜欢在可能的情况下使用@api.one
,因为我发现代码更加清晰(同样,对于计算和onchange方法,Odoo源通常使用@api.one
)。
在某些情况下,您只能使用@api.multi
:
如果您不仅想要循环记录,还希望只做一次:
@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"
如果返回值很重要。用@api.one
修饰的函数将始终返回一个列表(函数中返回值的列表作为迭代)。但在许多情况下,尤其是在与GUI交互时,您必须返回一个字典(例如带有警告)。在这些情况下,您必须使用@api.multi
。
答案 3 :(得分:0)
<强> @ api.multi 强>
装饰一个记录式方法,其中self
是一个记录集。该方法通常定义对记录的操作。这样的方法::
@api.multi
def method(self, args):
...
可以在记录和传统样式中调用,例如::
recs = model.browse(cr, uid, ids, context)
recs.method(args)
model.method(cr, uid, ids, args, context=context)
<强> @ api.model 强>
装饰一个记录样式的方法,其中self
是一个记录集,但其内容不相关,只有模型。这样的方法::
@api.model
def method(self, args):
...
可以在记录和传统样式中调用,例如::
recs = model.browse(cr, uid, ids, context)
recs.method(args)
model.method(cr, uid, args, context=context)
您可以在文件中找到这些装饰器的基本代码: odoo / api.py