宜兴通达竭诚为您服务。

通达科技 - 宜兴电脑维护及IT服务外包服务商

第九章:计算字段和Onchanges
  • 上传者: Administrator
  • 上传时间:2023年12月04日 08时34分33秒
摘要:
在任何Odoo模块中,  模型之间的关系 [1]  是一个关键组成部分。它们对于任何业务案例的建模都是必需的。然而,我们可能希望在给定模型内部的字段之间建立链接。有时一个字段的值是由其他字段的值决定的,有时我们希望帮助用户进行数据输入。 这些情况是由计算字段和onchange的概念支持的。虽然本章不 ......
正文 相关文章 请喝咖啡

    在任何Odoo模块中, 模型之间的关系 是一个关键组成部分。它们对于任何业务案例的建模都是必需的。然而,我们可能希望在给定模型内部的字段之间建立链接。有时一个字段的值是由其他字段的值决定的,有时我们希望帮助用户进行数据输入。

    这些情况是由计算字段和onchange的概念支持的。虽然本章不是技术上复杂的,但是这两个概念的语义非常重要。这也是我们第一次编写Python逻辑。到目前为止,我们除了类定义和字段声明之外还没有编写任何东西。

    计算字段

    参考: 有关此主题的文档可以在 计算字段 中找到。

     注解

    目标:在本节结束时:

    • 在物业模型中,应该计算总面积和最佳报价:

    计算字段
    • 在物业报价模型中,应该计算有效日期并进行更新:

    使用反函数计算字段

    在我们的房地产模块中,我们定义了居住面积和花园面积。因此,将总面积定义为两个字段的和是很自然的。我们将使用计算字段的概念来实现这一点,即给定字段的值将从其他字段的值计算得出。

    到目前为止,字段直接存储在数据库中并直接从数据库中检索。字段也可以是 计算的 。在这种情况下,字段的值不是从数据库中检索出来的,而是通过调用模型的一个方法来实时计算的。

    要创建一个计算字段,创建一个字段并将其属性 compute 设置为一个方法的名称。计算 方法应该为 self 中的每条记录设置计算字段的值。

    按照惯例, compute 方法是私有的,意味着它们不能从展示层调用,只能从业务层调用(参见 第一章:架构概述 )。私有方法的名称以下划线 _ 开头。

    依赖项

    计算字段的值通常取决于计算记录中其他字段的值。ORM希望开发人员使用装饰器 depends() 在计算方法中指定这些依赖关系。给定的依赖关系由ORM使用来触发字段的重新计算,只要其中一些依赖关系已被修改:

    from odoo import api, fields, models
    
    class TestComputed(models.Model):
        _name = "test.computed"
    
        total = fields.Float(compute="_compute_total")
        amount = fields.Float()
    
        @api.depends("amount")
        def _compute_total(self):
            for record in self:
                record.total = 2.0 * record.amount
    

     注解

    self is a collection.

    对象 self 是一个 recordset,即一个有序的记录集合。它支持集合的标准 Python 操作,例如 len(self) 和 iter(self),以及额外的集合操作,例如 recs1 | recs2

    迭代 self 逐个给出记录,其中每个记录本身是一个大小为1的集合。您可以使用点表示法访问/分配单个记录上的字段,例如 record.name 。

    在Odoo中可以找到许多计算字段的示例。 这里 <https://github.com/odoo/odoo/blob/713dd3777ca0ce9d121d5162a3d63de3237509f4/addons/account/models/account_move.py#L3420-L3423> __ 是一个简单的示例。

     Exercise

    计算总面积。

    • 将 total_area 字段添加到 estate.property。它被定义为 living_area 和 garden_area 的总和。

    • 将字段添加到表单视图中,如本节的第一张图片所示的 目标 。

    对于关系字段,可以使用字段路径作为依赖项::

    description = fields.Char(compute="_compute_description")
    partner_id = fields.Many2one("res.partner")
    
    @api.depends("partner_id.name")
    def _compute_description(self):
        for record in self:
            record.description = "Test for partner %s" % record.partner_id.name
    

    该示例使用了 Many2one,但同样适用于 Many2many 或 One2many。一个 示例可以在 这里 找到。

    让我们在我们的模块中尝试以下练习!

     Exercise

    计算最佳报价。

    • 将 best_price 字段添加到 estate.property。它被定义为报价中的最高价(即最大值)的 price

    • 将字段添加到表单视图中,如本节的第一张图片所示的 目标 。

    提示:你可能想尝试使用 mapped() 方法。查看 这里 以获取一个简单的示例。

    反函数

    您可能已经注意到,计算字段默认情况下是只读的。这是预期的,因为用户不应该设置值。

    在某些情况下,直接设置值仍然很有用。在我们的房地产示例中,我们可以为报价定义有效期限并设置有效日期。我们希望能够设置持续时间或日期,而不会影响另一个。

    为了支持这一点,Odoo 提供了使用 inverse 函数的能力::

    from odoo import api, fields, models
    
    class TestComputed(models.Model):
        _name = "test.computed"
    
        total = fields.Float(compute="_compute_total", inverse="_inverse_total")
        amount = fields.Float()
    
        @api.depends("amount")
        def _compute_total(self):
            for record in self:
                record.total = 2.0 * record.amount
    
        def _inverse_total(self):
            for record in self:
                record.amount = record.total / 2.0
    

    一个例子可以在 这里 找到。

    计算方法设置字段,而反向方法设置字段的依赖关系。

    请注意,当保存记录时,会调用 inverse 方法,而在其依赖项发生更改时,会调用 compute 方法。

     Exercise

    计算优惠的有效日期。

    • 在 estate.property.offer 模型中添加以下字段:

    字段

    类型

    默认

    有效性

    整数

    7

    截止日期

    日期

    在这里, date_deadline 是一个计算字段,它被定义为报价中两个字段的和: create_date 和 validity 。定义一个适当的反函数,以便用户可以设置日期或有效期。

    提示: create_date 只有在记录创建时才会填充,因此您需要一个备用方案来防止在创建时崩溃。

    • 将字段添加到表单视图和列表视图中,如本节的 目标 的第二张图片所示。

    附加信息

    计算字段默认情况下 不会存储 在数据库中。因此, 无法 在计算字段上进行搜索,除非定义了 search 方法。这个主题超出了本培训的范围,所以我们不会涉及它。一个示例可以在 这里 <https://github.com/odoo/odoo/blob/f011c9aacf3a3010c436d4e4f408cd9ae265de1b/addons/event/models/event_event.py#L188> __找到。

    另一种解决方案是使用 store=True 属性存储字段。虽然这通常很方便,但要注意可能会增加模型的计算负载。让我们重用我们的示例:

    description = fields.Char(compute="_compute_description", store=True)
    partner_id = fields.Many2one("res.partner")
    
    @api.depends("partner_id.name")
    def _compute_description(self):
        for record in self:
            record.description = "Test for partner %s" % record.partner_id.name
    

    每次合作伙伴的 name 发生变化时, description 会自动重新计算,适用于 所有引用它的记录 !当需要重新计算数百万条记录时,这可能会变得非常耗时。

    值得注意的是,计算字段可以依赖于另一个计算字段。ORM 足够智能,可以正确地按正确顺序重新计算所有依赖项… 但有时会以性能降低为代价。

    在定义计算字段时,通常需要考虑性能问题。计算字段越复杂(例如具有许多依赖关系或计算字段依赖于其他计算字段),计算所需的时间就越长。在定义计算字段之前,始终要花些时间评估其成本。大多数情况下,只有在您的代码到达生产服务器时,您才会意识到它会减慢整个过程的速度。这很不好 :-(

    触发器

    参考: 有关此主题的文档可以在 onchange() 中找到:

     注解

    目标:在本节结束时,启用花园将设置默认面积为10和朝向为北。

    触发事件

    在我们的房地产模块中,我们还想帮助用户进行数据输入。当设置了“花园”字段时,我们希望为花园面积和朝向提供默认值。此外,当取消设置“花园”字段时,我们希望花园面积重置为零,并删除朝向。在这种情况下,给定字段的值会修改其他字段的值。

    ‘onchange’ 机制提供了一种方法,使得客户端界面在用户填写字段值时,无需将任何内容保存到数据库即可更新表单。为了实现这一点,我们定义一个方法,其中 self 表示表单视图中的记录,并使用 onchange() 进行修饰,以指定触发它的字段。您对 self 进行的任何更改都将反映在表单上:

    from odoo import api, fields, models
    
    class TestOnchange(models.Model):
        _name = "test.onchange"
    
        name = fields.Char(string="Name")
        description = fields.Char(string="Description")
        partner_id = fields.Many2one("res.partner", string="Partner")
    
        @api.onchange("partner_id")
        def _onchange_partner_id(self):
            self.name = "Document for %s" % (self.partner_id.name)
            self.description = "Default description for %s" % (self.partner_id.name)
    

    在这个例子中,改变合作伙伴也会改变名称和描述的值。用户可以选择是否在之后改变名称和描述的值。还要注意的是,我们不会在 self 上循环,因为该方法只在表单视图中触发,而 self 始终是单个记录。

     Exercise

    设置花园面积和朝向的值。

    在 estate.property 模型中创建一个 onchange ,以便在将花园设置为 True 时为花园区域(10)和方向(North)设置值。当取消设置时,清除这些字段。

    附加信息

    Onchanges 方法也可以返回一个非阻塞的警告消息(示例)。

    如何使用它们?

    在使用计算字段和onchange时没有严格的规则。

    在许多情况下,计算字段和onchange都可以用来实现相同的结果。始终优先选择计算字段,因为它们也会在表单视图之外的上下文中触发。绝对不要使用onchange来向模型添加业务逻辑。这是一个 非常糟糕 的想法,因为当以编程方式创建记录时,onchange不会自动触发;它们只会在表单视图中触发。

    计算字段和onchange的常见陷阱是试图通过添加过多的逻辑来变得“过于聪明”。这可能会产生与预期相反的结果:最终用户会因所有自动化而感到困惑。

    计算字段往往更容易调试:这样的字段由给定的方法设置,因此很容易跟踪何时设置值。另一方面,onchange 可能会令人困惑:很难知道 onchange 的范围。由于多个 onchange 方法可能设置相同的字段,因此很容易跟踪值来自何处。

    使用存储的计算字段时,请注意依赖关系。当计算字段依赖于其他计算字段时,更改一个值可能会触发大量的重新计算。这会导致性能下降。

    在 下一章 中,我们将看到当按钮被点击时,我们如何触发一些业务逻辑。

    本文章从网上收集,如有侵权请联系tderp@tderp.com删除
  • 微信扫一扫,一分也是爱:
  • 微信

服务原则及地区范围

宜兴通达网络科技有限公司,地处中国宜兴环科园内,是一家高新技术企业。公司在企业网络维护和企业信息化建设与咨询方面,有10多年经验。

我公司愿与客户一道,力求彻底解决客户问题!
我们不是在给企业提供“头痛医头、脚痛医脚”的暂时解决方案,而是在部署根本性安全与稳定服务!!
我们愿携手客户,建立企业IT规划;杜绝随意安装系统、软件等操作;力求共同维护有序、安全、稳定的网络办公环境!!!
IT服务,服务是根本,客户是上帝;我们提供快速响应、快速上门、快速排查,提供优质高效的服务!!!!

通达科技提供全国范围内的服务,服务形式包括远程协助、电话咨询、电子邮件咨询、传真咨询、问答平台的问题解决等。

宜兴地区提供上门服务:

  • 市区服务:宜城街道、城北街道(屺亭街道)、新街街道、新庄街道、环科园、渚桥开发区
  • 市郊服务:张渚镇、西渚镇、太华镇、徐舍镇、官林镇、杨巷镇、新建镇、和桥镇、高塍镇、万石镇、周铁镇、芳桥镇、丁蜀镇、湖父镇。
  • 联系电话:189-21-343434
  • 在线沟通: