@api.one、@api.multi 和@api.model 有什么区别?

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

我对 Odoo 中的 @api.one@api.multi@api.model 感到困惑。

这三者有什么区别,它们的用例是什么?

api.one

此装饰器会自动为您在 RecordSet 的 Records 上循环。自己被重新定义为当前记录:

@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

方法装饰器需要根据你的方法需要定义,如果你想从方法中 return 字典那么你的方法必须包含 @api.multi.

参考New API Guideline

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 被认为是在您需要对模型本身做某事而不需要 modify/check 某些确切模型的 record/records 时使用。例如,可能有 return 一些关于模型结构的元信息或一些辅助方法等的方法。同样在文档中,据说这个 api 在从旧的 [=40] 迁移时很好用=],因为它 "politely" 将代码转换为新的 api。同样根据我自己的经验,如果您需要 return 某些东西的方法,model 装饰器对它很有用。 api.one return 是一个空列表,因此在应该 return 某些东西的方法上使用 api.one 时可能会导致意外行为。

更多信息:http://odoo-new-api-guide-line.readthedocs.org/en/latest/decorator.html

  • one、multi和model的区别

您实际上可以 调用包含多个记录的 RecordSet 的 @api.one 方法。唯一的区别是 @api.one 记录的循环将在您定义的函数之外完成,而 self 装饰器将一条一条地传递 RecordSet 中的每条记录。

例如,让我们在模型中定义两个函数 example.model:

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

@api.multi
def 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()

会 return:

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"

即使在记录集中使用更多记录调用他们。

另一方面,你不使用 any 装饰器,那么它不能被调用多于(或少于)一条记录,否则它会抱怨并可能停止出现错误。

@api.model 是一个完全不同的故事:只有当您只希望用空记录集调用它时,才应该使用这个装饰器。

  • 什么时候用哪个

如果你期望一个非空的RecordSet作为输入值,那么在很多情况下,你可以同时使用@api.one@api.multi,这只是个人喜好的问题。我个人更喜欢在可能的情况下使用 @api.one,因为我发现这样代码更清晰(另外,对于计算和 onchange 方法,Odoo 源通常使用 @api.one)。

但在某些情况下您只能使用 @api.multi

  1. 如果您不仅想循环记录,还想只做一次:

     @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. 如果 return 值很重要。用 @api.one 装饰的函数将 总是 return 一个列表(函数中 return 值的列表作为迭代)。但在许多情况下,尤其是在与 GUI 交互时,您将不得不 return 字典(例如带有警告)。在这些情况下,您将不得不使用 @api.multi.

@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