模块 ODOO中的Related字段及Computed字段原理
Related 字段属性在数据库中是没有存储的,均是每次调用此字段时,通过函数计算出来。 所以,若想要让其他函数引用此 related 字段,必须添加 store = True 属性(存储字段的优点是,对该字段的搜索是由数据库本身完成的。)。 通过引用字段获取值来作为本字段的值 Inverse反参数的使用非常简单。通常,计算字段是只读的,因为它从记录集即时计算值。如果您需要在 计算字段上进行手动输入,可以通过给出反函数来完成。因此,当字段被写入/创建时,它会触发对修饰函数的调用。它反转计算并设置相关字段。 Invserse 通俗点讲的话,他是 Compute 的相反设置.我们在 field 中设置了它对应的 Compute 计算方法,那么这个字段就变成了只读的,这时候我们可以设置 inverse,来达到为该字段赋值的目的。设置了 inverse 这个,字段就可以在前端直接编辑,赋值就是通过这个 inverse 设置的方法。 upper = fields.Char(compute='_compute_upper', inverse='_inverse_upper', search='_search_upper') @api.depends('employee_id') def _compute_upper(self): for rec in self: rec.upper = rec.employee_name.upper() if rec.employee_name else False def _inverse_upper(self): for rec in self: rec.employee_name = rec.upper.lower() if rec.upper else False Search默认情况下,计算字段不存储到数据库中,而是动态计算。添加属性“store=true”将在数据库 中存储字段值。 因此,不能正常搜索未存储在数据库中的计算字段,要启用搜索,必须显式定义搜索函数。这可以通过在计算字段中添加“搜索”参数来实现。如果我们添加一个方法来搜索计算字段,那么在 对模型进行实际搜索之前,在处理域时会调用该方法。 standard_price = fields.Float( 'Cost', compute='_compute_standard_price', inverse='_set_standard_price', search ='_search_standard_price', digits=dp.get_precision('Product Price'), groups="base.group_user", ) def _search_standard_price(self, operator, value): products = self.env['product.product'].search([('standard_price', operator, value)], limit=None) return [('id', 'in', products.mapped('product_tmpl_id').ids)]- 常用装饰器、
- 处理记录集,在这种情况下,应该使用@api.multi装饰器,并且可以使用self参数以方便地获取记录集
- 在Odoo中,对于类型这种静态方法,可使用@api.model装饰器,这种方法的self参数是一个对象的引用而非一个记录集。但使用@api.model装饰的方法不能用于用户界面的按扭
- @api.depends(字段1,字段2,…)装饰器用于计算字段(computed field),可以用于标示需要被触发的计算。使用此装饰器应该注意计算字段(computed field)必须被赋值,否则会就报错 ,计算字段的值通常取决于所在记录行的其它字段的值
- ·@api.constraints(字段1,字段2,…)用于评估和检查,当参数字段的值发生变化时,会进行检查,如果检查规则不通过,则字段值不会发生变化,并且会报出一个异常。(用于校验,弹框报错)
- @api.onchange(字段1,字段2,…)用于系统在与用户进行交互时自动更新相关联的字段 需要注意的是,这个方法的具体名字与方法的触发没有直接关联性,Odoo主要是通过方法的装饰器来找到方法的。在onchange方法中,参数self代表的是包含了form所有可编辑字段的单一记录
- 上述几个装饰器,除了onchange可选地返回一个字典之外,其他的都不需要返回任何值。onchange返回的数据往往也是返回给UI的一些提示信息。
- ORM内置方法
- ·.create(values)方法可以创建新记录并且可以通过return方法返回。
- ·.write(values)方法可用于更新记录,并且不需要返回值。
- ·.unlink()方法可从数据库删除记录,不需要返回值。
- 上述方法中的values参数是字典类型,执行方法时可将字段与字段值进行对照来匹配。一般情况下,我们会集成这些方法并且增加一些自己需要的业务逻辑处理,当这些方法被触发时,我们新增的逻辑将会得到执行。新增的代码既可以在继承的代码之前,也可以在继承的代码之后。
- read([fields])与browse方法类似,但是read方法返回的记录仅包括参数中包含的字段。返回数据的每一行记录都是字典的形式
- search_read([domain],[fields],offset=0,limit=None,order=None)方法可以在结果记录集上面再次执行查找的操作
- load([fields],[data])可用于从CSV文件导入数据。第一个参数列出需要的字段,列的名称直接使用CSV文件第一行的名称。而第二个参数则可以列出需要的记录,每一行记录都可以由其各列的数据组成
- export_data([fields],raw_data=False)用于从页面端导出数据。这种方法将返回一个字典,字段的数值键包含一个行列表
- name_get()方法可返回(ID,name)元组组成的列表,每个元组代表一行记录,该方法可默认用于获取display_name
- ·name_search(name='',args=None,operator='ilike',limit=100)可返回(ID,name)元组组成的列表,显示名称将会与参数name的文本进行匹配进而定位记录,一般应用会根据在UI上输入的一个字段去获取该记录的其他字段
- name_create(name)可用于根据名称快速创建一行新记录,该记录在创建时仅具有名称字段,使用的时候可以继承扩展此方法,用于在创建记录时为一些字段设置默认值。
- ·default_get([fields])可返回一个具有待创建新记录默认值的字典 比如根据当前用户或者会话上下文的变量 ,
- @api.model
- def fields_get(self, allfields=None, attributes=None):
- res = super(OkrManageLine, self).fields_get(allfields, attributes)
- for key, value in res.items():
- if key == 'create_date': #res={"create_date":value1,'write_date':value2}
- res[key]['string'] = '创建时间'
- elif key == 'write_date':
- res[key]['string'] = '最后更新时间'
- if key == 'create_date': #res={"create_date":value1,'write_date':value2}
- return res
- 调用父类fields_get的返回值是议程字典,我们可以通过判断字段的名称对其在筛选和分组中的显示标签进行调整
- 在筛选和分组中对一些字段进行隐藏实现格式如下:
- @api.model
- def fields_get(self, allfields=None, attributes=None):
- # 过滤掉筛选中不显示项
- res = super(SupplierInvoiceRecordPivot, self).fields_get(allfields, attributes)
- filter_field = ['create_uid', 'write_date', 'create_date', 'write_uid', 'uid']
- for key, value in res.items():
- if key in filter_field:
- res[key]['searchable'] = False
- res[key]['sortable'] = False
- if key in filter_field:
- return res
- res[key][‘searchable’] = False 设置字段 key 在筛选中不可见
- res[key][‘sortable’] = False 设置字段key在分组中不可见
- self引用的多个记录集,既有环境信息的记录集、用户浏览数据的记录集,又有上下文(context)信息等
- 使用self.env来查看当前用户运行的环境信息
- 事务和底层SQL
- 在前端中context可以将信息从一个视图传递到下一个。比如将上一个窗体的记录ID,在按钮点击动作完成后传递到下一个窗体。在服务器端,记录集的字段值可以依赖context提供的本地设置 context也可以为服务器端提供一些信号信息,比如将关键字active_test的值设置为False时,ORM的search方法在执行时就不会过滤inactive状态的记录。
- context在客户端可以用来设置目标视图的默认值或激活默认筛选器,可以使用以default_或default_search_开头的关键字来完成这种设置
- domain表达式的就较为简单了,可以是以下几种
- search()方法可获取一个domain表达式,并返回一个记录集记录匹配这些条件 search()方法可获取一个domain表达式,并返回一个记录集记录匹配这些条件
- 为此,可以使用search_count()来返回记录计数而不是记录集
- copy()可复制一个已有的记录;并且可带有一个可选的参数和一个带有值的字典 如果模型中的字段属性copy设置为False,则不会被复制
- ·fields.Date.today()返回当前日期的字符串格式
- ·fields.Datetime.now()返回一个带有当前datetime的字符串
- fields.Date.context_today(record,timestamp=None)返回一个在会话的上下文中使用的当前日期
- 为了方便格式之间的转换,fields.Date和fields.Datetime提供了如下功能。
- 如果x是一个单例记录集,而the_recordset是一个包含许多记录的记录集,那么可以使用它进行如下操作:
- ·recordset.filtered(func)返回一个经过过滤的记录集。
- 如何对记录集进行操作
- 在多对一的情况下,值可以是单例或空记录集。在这两种情况下,我们都可以直接访问它们的字段值。
- 一对多字段,它们的值也可以用记录集来进行分配,这里允许一个任意大小的记录集