Skip to content
  • Categories
  • Tags
  • Popular
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (Flatly)
  • No Skin
Collapse

Odoo 中文社区

  1. Home
  2. Categories
  3. Odoo 培训
  4. 至死都被误解的ODOO的API

至死都被误解的ODOO的API

Scheduled Pinned Locked Moved Odoo 培训
api.oneapi.multiapi.model
1 Posts 1 Posters 584 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • digitalsatoriD Offline
    digitalsatoriD Offline
    digitalsatori 管理员
    wrote on last edited by digitalsatori
    #1

    api.one api.multi 已淘汰

    首先需要澄清,随着当前最新的Odoo版本V13.0发布以后。 api.one 和 api.multi 作为Odoo的实体类方法的装饰器的用法已经淘汰。在V13.0以后的Odoo版本中使用这两个装饰器,系统会报错。
    很多人会说,你这不是闲得没事干吗?讨论一个已经淘汰的语法应用有什么意义呢?其实,这些语法虽然被淘汰了,但是要知道最新版本的Odoo的实体类方法默认就是工作在过去 api.multi 这种模式下,而 api.model 也继续在工作。所以,我们对这些淘汰语法的讨论可以加深对当前新语法的认识。

    api.one - Odoo最被误解的语法

    api.one 的用法是Odoo中最被误解的一个。以至于到V9.0发布的时候Odoo就建议大家放弃吧,不要再乱用了, 全部用 api.multi 就好。如果不做点解释这个语法是妥妥的带着完全的误解走入坟墓的那个。

    对这个装饰器的错误理解我认为主要是因为其名字的误导,而且还存在一个跟它相对的 api.multi 。所以,大多数的人的直觉就是认为 api.one 装饰的方法就是工作在只有单个Record的情况下。而事实是正相反, api.one 设计的初衷正是为了简化处理多实例的Record Set的。比如:

    class Category(models.Model):
        _name = 'test_new_api.category'
    
        name = fields.Char(required=True)
        parent = fields.Many2one('test_new_api.category', ondelete='cascade')
        display_name = fields.Char(compute='_compute_display_name', inverse='_inverse_display_name')
    
        @api.one
        @api.depends('name', 'parent.display_name')     # this definition is recursive
        def _compute_display_name(self):
            if self.parent:
                self.display_name = self.parent.display_name + ' / ' + self.name
            else:
                self.display_name = self.name
    

    在上面这个简单的例子中,display_name 是一个计算字段,作用是将所有上级分类的名称连接显示。当在分类对象的表单视图上时 self 就是单个记录,而在Tree视图时,self 就是包含多个记录的记录集。上面的例子如果换成 api.multi 的话就要保证方法内一定要做循环,否则在Tree视图时就会报错,也就是:

    
        @api.multi
        @api.depends('name', 'parent.display_name')     # this definition is recursive
        def _compute_display_name(self):
            for rec in self:
                if rec.parent:
                    rec.display_name = rec.parent.display_name + ' / ' + rec.name
                else:
                    rec.display_name = rec.name
    

    而 api.one 则可以**“假装”** self 是单条记录这样处理,装饰器会自动对记录集做循环,并将函数结果归集到列表中。这其实的确会让程序员省事不少,因为在Odoo中绝大多数情况类方法要考虑对多记录的循环处理的。所以因为起名不慎,导致了其早夭。以后开发者就老老实实的,不厌其烦的象上面这样循环吧。

    api.multi 和 self.ensure_one()

    比如下面的例子:

      @api.multi
      def action_done(self):
          self.ensure_one()
          self.state = 'done'
          ....
    

    上面这段代码又是 multi (多个), 又是 ensure_one (保证一个) ,好分裂啊。可见,multi 并不是说我们都是工作在多实例的记录集上,而是既可能是单例记录也可能是多例记录集。比如上面例子中,这是一个表单上的确认按钮对应的方法,所以我们需要确保 self 只能是单例(否则就要做循环),这个 self.ensure_one 就是用来确保 self 不是多例的。

    幸亏在V13之后我们不用再写 @api.multi 装饰器了,默认就是工作在它所指定的方式下。否则,这种分裂语言在Odoo中真的会触目惊心。

    api.model 的用法

    搞明白了上面的概念, api.model 就不复杂了。 api.model 使用的方法一直没有发生变化。上面的使用 api.one 或 api.multi 装饰器装饰的方法,或者最新的不带装饰器(实际就是 api.multi)的方法中的 self 都是记录集,就是model所对应的数据库表中的记录。而 api.model 所装饰的方法中的 self 是指model本身。比如:

    @api.model
    def create(self):
        ...
    
    def write(self):
        ...
    

    上面 create 方法就要用 api.model 装饰,因为在调用 create 方法时还没有记录集呢。而 write 方法当然是对已有记录集的更新,所以不加装饰器(也就是隐性的 api.multi 装饰的方法)。

    希望上面的解释对您理解Odoo的API有帮助。

    【上海先安科技】(tony AT openerp.cn)

    1 Reply Last reply
    0

    • Login

    • Don't have an account? Register

    • Login or register to search.
    • First post
      Last post
    0
    • Categories
    • Tags
    • Popular
    • Users
    • Groups