Odoo 16 中新增的 Properties 字段

Odoo 16 正式发布已经有一段时间了,最近也在基于最新的版本做了一些开发,顺便学习了一下 Owl 并且开发了个小模块作为练习。在翻看 Project 这个应用的时候,发现在模型 project.task 上有一个 Properties 类型的字段,在之前的版本中是没有见到过的,于是翻阅了一下源码,在这里做个记录。
""" Field that contains a list of properties (aka "sub-field") based on
a definition defined on a container. Properties are pseudo-fields, acting
like Odoo fields but without being independently stored in database.

This field allows a light customization based on a container record. Used
for relationships such as <project.project> / <project.task>,... New
properties can be created on the fly without changing the structure of the
database.

The "definition_record" define the field used to find the container of the
current record. The container must have a :class:`~odoo.fields.PropertiesDefinition`
field "definition_record_field" that contains the properties definition
(type of each property, default value)...

Only the value of each property is stored on the child. When we read the
properties field, we read the definition on the container and merge it with
the value of the child. That way the web client has access to the full
field definition (property type, ...).
"""
odoo/fields.py 中可以找到 Properties 类的定义,从注释里可以大致了解这个字段类型的一些基本信息:
  • 适合轻度的自定义需求
  • 字段包含了“容器”定义好的属性
  • 这些属性表现和 Odoo 字段一样但是并不单独存储在数据库中(数据库表中不会有对应的列)
  • 在一组有关联关系的模型中使用,其中一方为“容器”(如 project.projectporject.task 的关系)
  • 需要配合“容器”中定义的 PropertiesDefinition 类型字段一起使用(存储了属性的定义)
  • 属性的值会被存储在子记录中(和“容器”关联的记录,定义了 Properties 字段的模型的记录)
  • 读取字段时会将“容器”的属性定义和子记录的字段值合并
实际看一下例子可能会更加容易理解这里面提到的一些概念,我们可以直接安装好项目模块,然后打开任意的任务记录,随意添加一些自定义属性试试。
notion image
上面截图中添加了三个属性,其中两个为 Char 一个为 Many2one 类型,分别来看一下属性的定义和存储的属性值是怎样的
# project.project 的 task_properties_definition 字段中存储的属性定义
[
    {
        "default":"",
        "type":"char",
        "name":"93be0af4ab70ca68",
        "string":"Prop1"
    },
    {
        "default":"",
        "type":"char",
        "name":"90bdf877fbbd91a7",
        "string":"Prop2"
    },
    {
        "domain":false,
        "name":"a7e6b811e9401c30",
        "default":false,
        "comodel":"hr.employee",
        "type":"many2one",
        "string":"Prop3"
    }
]

# project.task 的 task_properties 存储的属性值
{'90bdf877fbbd91a7': 'P2', '93be0af4ab70ca68': 'P1', 'a7e6b811e9401c30': 3}

# 从 read 接口中读取到 project.task 的 task_properties 值
[
  {
    "name": "93be0af4ab70ca68",
    "type": "char",
    "string": "Prop1",
    "default": "",
    "value": "P1"
  },
  {
    "name": "90bdf877fbbd91a7",
    "type": "char",
    "string": "Prop2",
    "default": "",
    "value": "P2"
  },
  {
    "name": "a7e6b811e9401c30",
    "type": "many2one",
    "domain": false,
    "string": "Prop3",
    "comodel": "hr.employee",
    "default": false,
    "value": [
      3,
      "Anita Oliver"
    ]
  }
]
从上面的数据结构可以看到属性的定义和属性值,是分别存储的,而实际在通过 ORM 方法获取的时候,Odoo 会将它们合并返回,这一点从源码中的 convert_to_record()convert_to_read() 中可以看到。
在项目模块上使用这个类型的字段对任务添加自定义属性,让我联想到了 Jira 的任务管理,不同项目可以设置不同的任务属性,具有很强的可变性,不知道 Odoo 是不是有所参照?

©️
 本文采用 CC BY-NC-ND 4.0 许可协议。转载或引用时请遵守协议内容!

© Ruter Lü 2016 - 2023