一、@api.model
使所装饰方法这段代码中的self仅代表模型本身,不含任何记录信息
--- 使用场景
1.各种类方法和静态方法,这种方法不需要具体的实例对象来调用和执行(常见的如 create, search_read,name_search,default=的计算方法,search=的方法等等)
二、@api.depends
--- 使用场景
1.常见用于计算字段中,但是计算方法也可以不用这个装饰器,那么区别在哪儿呢?
这里就要简单说下odoo计算字段的运行原理:计算字段是在运行时动态计算的,因此不在数 据库中存储、默认无法对计算字段进行写操作。你需要自己对计算字段添加可写 (readonly=False)、可搜索(search=函数或者store=True)、可存储(store=True)的支持。
但是计算字段添加了 store=True 后它就不会每次刷新页面的时候计算一次了,这时就需要用 到depends装饰器,这样每次depends关联的字段发生改变,就会重新计算一次。(计算函数 在运行时动态计算,但ORM使用缓存来避免在每次访问值时的低效重计算。因此,它需要知 道所依赖的其它字段。它使用@depends装饰器来监测缓存值何时应置为无效并重新计算)
很多计算方法不需要添加depends装饰器,因为他们需要实时变化改字段的值,比如需要根据当前日期来计算值的字段。
计算方法特性:需要遍历,无返回值,如果未添加store=True则必须计算出计算字段的值,否则报错 。
值得一提的是,depends装饰器的参数可以是python表达式,例如下面这样的
@api.depends(lambda self: self._get_all_date_qty_fields() + ['sale_lines', 'sale_lines.state', 'sale_lines.qty_delivered'])
def _compute_undelivered_qty(self):
qty_name_list = self._get_all_date_qty_fields()
for order in self:
delivered_qty = sum(order.sale_lines.mapped('qty_delivered'))
order.undelivered_qty = sum([getattr(order, qty_field) for qty_field in qty_name_list]) - delivered_qty
三、@api.onchange
--- 使用场景
1.常用于onchange方法,关联多个字段,当字段发生变化后,产生相应的逻辑。
onchane方法特性:有返回值(odoo17及之后的版本不再支持返回domain了),如返回一个警示,或者返回一个字段筛选,如下
@api.onchange('property_cost_method')
def onchange_property_valuation(self):
if not self._origin:
# don't display the warning when creating a product category
return
return {
'warning': {
'title': _("Warning"),
'message': _("Changing your cost method is an important change that will impact your inventory valuation. Are you sure you want to make that change?"),
}
}
@api.onchange('product_id')
def onchange_domain(self):
if self.product_id:
order_ids = self.env['sale.order'].search([('product_id', '=', self.product_id.id)])
ly = []
if order_ids:
for order in order_ids:
if order.state == 'sale':
ly.append(order.id)
order_domain = [('id', 'in', ly)]
domain = {'check_sale_id': order_domain}
return {'domain': domain}
四、@api.constrains
--- 使用场景
1.给字段添加约束。
Odoo支持两种不同类型的约束:
a.数据库级别的约束检查
b.服务端级别的约束检查
数据库级别的约束如下:
_sql_constraints = [('name_unique', 'unique(name)', '名称已经存在')]
服务端级别的约束就可以用到constrains装饰器,如下:
@api.constrains('new_quantity')
def check_new_quantity(self):
if any(wizard.new_quantity < 0 for wizard in self):
raise UserError(_('数量不能为负数.'))
还可以在create,write,onchange等方法里面给字段添加约束。
五、@api.one和@api.multi
--- 使用场景
@api.one:用于self为单一记录的情况,意思是指:self仅代表当前正在操作的记录
@api.multi:用于self是多个记录的合集。因此,常使用for或者self.ensure_one(),如在tree视 图中点选多条记录,然后执行某个方法,那么那个方法必须用@api.multi修饰,而参数中的 self则代表选中的的多条记录
这两个装饰器在目前版本的odoo中已经废弃