Odoo 模型字段自动计算(compute)

在odoo的ORM创建数据字段的过程中,我们会经常需要定义一些字段用来计算某一些字段只和或其他计算结果。

今天介绍一个很好用的方法compute计算属性,这个方法其实是属于写在odoo fields中的属性,但是因为非常常用,还涉及ORM中的方法所以今天就单独列出来详细讲解它的用法。

 如何使用odoo compute属性实现自动计算字段

我们看下面的案例

class FandxProduct(models.Model):
    _name = "fandx.product"

    name = fields.Char("产品名称")
    nums = fields.Integer("数量")
    unit_price = fields.Float("产品单位价格")

现在有个需求,这是一个产品表,我们需要计算他的每一个产品的总价格(产品单位价格*数量),这时候就要用到我们的主角compute属性,下面看案例。

class FandxProduct(models.Model):
    _name = "fandx.product"

    name = fields.Char("产品名称")
    nums = fields.Integer("数量")
    unit_price = fields.Float("产品单位价格")
    # 使用_compute_all_price
    all_price = fields.Float("产品总价格", compute="_compute_all_price")

    def _compute_all_price(self):
        # self取值默认是multi,所以需要循环拿到每一个record的值
        for record in self:
            # 计算每一个record的all_price的值进行赋值
            record.all_price = record.unit_price * record.nums

在字段中定义属性compute并指向计算方法,在数据创建的时候会自动计算这个字段的数据。

这样我们在XML中使用all_price就可以获取到产品的总价格,但是这里还有一个问题。

数据库中是没有进行持久存储的,那么数据数据量一大,每次渲染页面都要进行计算,这样是非常消耗服务器性能的,所以我们就要将计算的字段给存储起来。

如何存储odoo compute计算字段的值

方法很简单,只需要在定义的field中加上store字段,这样就会把计算到的结果给存储到数据库中。

class FandxProduct(models.Model):
    _name = "fandx.product"

    name = fields.Char("产品名称")
    nums = fields.Integer("数量")
    unit_price = fields.Float("产品单位价格")
    # 使用_compute_all_price
    # 在字段中加上store = True实现数据的持久化
    all_price = fields.Float("产品总价格", compute="_compute_all_price", store=True)

    def _compute_all_price(self):
        # self取值默认是multi,所以需要循环拿到每一个record的值
        for record in self:
            # 计算每一个record的all_price的值进行赋值
            record.all_price = record.unit_price * record.nums

这样我们在数据库中就有了all_price的字段来记录产品总价格。

但是现在又出现一个问题,计算字段是计算出了我们的结果,但是如果nums改变,或者unit_price改变了,计算字段并不会改变怎么办!

compute配合使用depends监听数据变化

class FandxProduct(models.Model):
    _name = "fandx.product"

    name = fields.Char("产品名称")
    nums = fields.Integer("数量")
    unit_price = fields.Float("产品单位价格")
    # 使用_compute_all_price
    # 在字段中加上store = True实现数据的持久化
    all_price = fields.Float("产品总价格", compute="_compute_all_price", store=True)

    # 将nums、unit_price字段进行监听,在数据变动的时候再次执行compute指向的方法进行重新赋值计算。
    @api.depends('nums', 'unit_price')
    def _compute_all_price(self):
        # self取值默认是multi,所以需要循环拿到每一个record的值
        for record in self:
            # 计算每一个record的all_price的值进行赋值
            record.all_price = record.unit_price * record.nums

到这里就基本实现了compute的所有经常使用的方法,下面一般会配合compute一起使用的属性inverse

odoo中逆向计算inverse属性使用详解

上面讲解了compute方法是用来计算对应的数据字段的。

inverse方法其实就是compute的逆向方法,默认情况下xml中对应的compute计算字段是readonly的。

当我们加上inverse逆向计算的时候,那么就可以在XML中输入对应的值,然后系统会走inverse对应的方法。

class FandxProduct(models.Model):
    _name = "fandx.product"

    name = fields.Char("产品名称")
    nums = fields.Integer("数量")
    unit_price = fields.Float("产品单位价格")
    # 使用_compute_all_price
    # 在字段中加上store = True实现数据的持久化
    all_price = fields.Float("产品总价格", compute="_compute_all_price", inverse='_set_unit_price', store=True)

    # 将nums、unit_price字段进行监听,在数据变动的时候再次执行compute指向的方法进行重新赋值计算。
    @api.depends('nums', 'unit_price')
    def _compute_all_price(self):
        # self取值默认是multi,所以需要循环拿到每一个record的值
        for record in self:
            # 计算每一个record的all_price的值进行赋值
            record.all_price = record.unit_price * record.nums

    def _set_unit_price(self):
        for record in self:
            if not all([record.nums, record.all_price]):
                continue
            
            # 当我们手动修改all_price的值的时候,我们就可以逆向去计算出unit_price的值,进行重新赋值。
            record.unit_price = record.all_price / record.nums

总结

  1. odoo的compute可以实现我们对数据字段自动计算的需求。
  2. fields中加入store属性可以实现数据的持久化存储。
  3. compute计算字段在持久化存储之后不会在自动计算,需要我们配合depends来监听指定计算字段在数据改动的时候重新计算数据字段。
  4. inverse方法可以帮助我们解决compute计算字段readonly的问题,并在输入对应的字段进行逆向计算之前的字段。
  5. compute字段默认是store为False的所有search是无效的,还可以指定search的方式实现搜索。这里就不去细讲了,很简单也不常用。
  6. 还有compute_sudo属性可以设置字段在使用的时候是否以超级管理员的方式来进行计算,这里store=True的时候默认为True,否则默认为False,了解一下就可以了。
上一篇:云笔记Fusion Compute架构


下一篇:flutter入门之理解Isolate及compute