第四章 应用模型中,我们学习了如何在自定义模块中声明或继承业务模型。该章中的各小节涵盖了为计算字段编写方法,以及编写约束字段值的方法。本章中将集中讲解服务端开发的基础,有Odoo方法定义、数据集操作及扩展已继承方法。这样我们就可以在Odoo中添加及修改业务逻辑了。

本章中,我们将讲解如下内容:

  • 定义模型方法及使用API装饰器
  • 向用户报出错误
  • 获取其它模型的空记录集
  • 新建记录
  • 更新记录集中记录值
  • 搜索记录
  • 合并记录集
  • 过滤记录集
  • 遍历记录集关联
  • 记录集排序
  • 继承模型中定义的业务逻辑
  • 继承write()和create()
  • 自定义记录的搜索方式
  • 使用read_group()从组中获取数据

技术准备

本章的技术要求包括Odoo在线平台。

本章中所使用的代码可以在如下GitHub仓库中下载:https://github.com/alanhou/odoo14-cookbook

定义模型方法及使用API装饰器

Odoo模型中,类是字段定义和业务逻辑方法的混合体。第四章 应用模型中我们学习了如何在模型中添加字段。下面就来学习如何在模型中添加方法和业务逻辑。

本节中,我们来学习如何编写可由用户界面中按钮或应用其它代码块调用的方法。这一方法会操作图书并执行所需的动作来修改所选图书的状态。

**译者注:**本节中初始代码为第三章结束时的代码:GitHub传送门。开始本节前请卸载掉之前安装的应用,重新进行安装,否则可能会出现意想不到的各种错误。

准备工作

本节假定你已有准备好了实例,包含第三章 创建Odoo插件模块中所描述的my_library插件模块。需要在LibraryBook模型中添加一个state字段,定义如下:

from odoo import models, fields, api
class LibraryBook(models.Model):
     # [...]
     state = fields.Selection([
         ('draft', 'Unavailable'),
         ('available', 'Available'),
         ('borrowed', 'Borrowed'),
         ('lost', 'Lost')],
         'State', default="draft")

参见第三章 创建Odoo插件模块添加模型一节获取更详细信息。

如何实现…

要定义方法来修改所选图书的状态,你需要在模型定义中添加如下代码:

  1. 添加一个帮助方法来查看是否允许状态转换:

    @api.model
    def is_allowed_transition(self, old_state, new_state):
         allowed = [('draft', 'available'),
             ('available', 'borrowed'),
             ('borrowed', 'available'),
             ('available', 'lost'),
             ('borrowed', 'lost'),
             ('lost', 'available')]
         return (old_state, new_state) in allowed
    
  2. 添加方法来修改一些书籍的状态为所传参数的新状态:

    @api.multi
    def change_state(self, new_state):
         for book in self:
             if book.is_allowed_transition(book.state, new_state):
                book.state = new_state
             else:
                continue
    
  3. 添加方法来通过调用change_state方法修改图书状态:

    def make_available(self):
        self.change_state('available')
    
    def make_borrowed(self):
        self.change_state('borrowed')
    
    def make_lost(self):
        self.change_state('lost')
    
  4. 视图中添加按钮和状态栏。这会帮助我们从用户界面中触发这些方法:

    <form>
    ...
        <header>
            <button name="make_available" string="Make Available" type="object"/>
            <button name="make_borrowed" string="Make Borrowed" type="object"/>
            <button name="make_lost" string="Make Lost" type="object"/>
            <field name="state" widget="statusbar"/>
        </header>
    ...
    </form>
    

更新或安装该模块来让这些修改生效。

运行原理…

本节中的代码定义了一些方法。它们是常规的Python方法,带有self作为其第一个参数,也可以带有其它参数。这些方法通过odoo.api模块中的装饰器进行装饰。

📝这些中很多装饰器是在Odoo 9.0中引入的,用于兼容老框架和新框架。在Odoo 10.0中,不再支持老的 API 了,但一些装饰器,比如@api.model,仍在使用。

在编写一个新方法时,如果不使用装饰器,方法会对记录集执行。在这类方法中,self是可以引用任意数量数据库记录的记录集(包括空记录集),代码经常会遍历self中的记录来对每条记录进行操作。

@api.model装饰器也类似,但它用于仅仅是模型很重要而非方法所不操作的记录集中的内容的方法。它的概念类似于Python的@classmethod装饰器。

在第1步中,我们创建了is_allowed_transition() 方法。这个方法的目的是验证从一个状态到另一个状态的转换是否有效。allowed列表中的元组即为可使用转换。例如,我们不会允许lost到borrow的转换,因此没有加入(‘lost, ‘borrowed’)。

第2步中,我们创建了 change_state()方法。这个方法的用途是修改图书的状态。调用该方法时,它将图书的状态修改为给定new_state参数的状态。仅在允许进行转换时它才会修改图书状态。这里使用了for循环是因为self可以 包含多个记录集。

在第3步中,我们创建了一些通过调用change_state()方法来修改图书状态的方法。本例中,方法会由添加到用户界面中的按钮所触发。

第4步中,我们添加在视图中添加了