跳至内容

Odoo 19 技术教程:如何在 Odoo 19 中使用模型属性

如何在 Odoo 19 中使用模型属性

        你是否曾思考过,是什么让 Odoo 模型具备如此出色的适应性和高效性?无论你已经在使用 Odoo 进行开发,还是刚刚开始探索,熟练掌握模型属性都将为你带来颠覆性的提升。在 Odoo 19 中,这些属性是业务逻辑的基石——它们控制着数据的存储方式、系统的响应逻辑,甚至记录在界面中的展示形式和行为。理解这些属性,你就能真正掌握定制化应用的核心能力。

        你可以将模型属性理解为指导 Odoo 处理数据的指令集。它们定义了数据是存储到数据库、保留在内存中快速处理,还是作为其他模型继承的基础结构。这套灵活的系统,正是 Odoo 成为强大且可定制化业务应用开发平台的核心原因之一。

Odoo 模型的三大核心类型

在深入学习各类属性之前,我们先了解构成所有 Odoo 应用基础的三种核心模型类型:

1. 普通模型(Model)—— 应用的核心主力

持久化存储到数据库的普通模型,是 Odoo 应用的基础核心。这类模型代表你的核心业务实体,例如客户、产品、销售订单和发票。通过这些模型创建的每一条记录都会永久保存在数据库中,且跨会话持久生效。当你创建客户记录或生成发票时,就是在使用普通模型。

适用场景:客户档案、产品目录、销售订单、会计分录——所有需要永久存储和查询的数据。

# -*- coding: utf-8 -*-
class LibraryBook(models.Model):
   _name = 'library.book'  # 模型唯一技术名称
   _description = '图书馆图书管理'  # 可读的模型名称
   _table = 'library_book'  # 自定义数据库表名(可选)
   _rec_name = 'name'  # 用作记录展示名称的字段
   _order = 'name asc'  # 默认排序规则
   _inherit = []  # 继承的现有模型(如需)
   _inherits = {}  # 委托继承(父模型: 关联ID字段)
   _abstract = False  # 抽象模型设为 True
   _transient = False  # 临时向导模型设为 True
   _auto = True  # 自动创建数据库表
   _register = True  # 在 ORM 中注册模型
   _parent_name = 'parent_id'  # 层级关系关联字段
   _parent_store = False  # 启用树形结构优化
   _active_name = 'active'  # 归档/取消归档使用的字段
   _check_company_auto = True  # 强制多公司数据一致性
   _allow_sudo_commands = True  # 允许对该模型执行 sudo 操作
   _rec_names_search = ['name', 'isbn']  # 多对一字段搜索时使用的字段
   # SQL 视图相关(仅当 _auto = False 时使用)
   _table_query = None  # 为基于视图的模型定义 SQL 查询
   _depends = {}  # SQL 视图模型的依赖关系
   # 字段定义
   name = fields.Char(string="图书名称", required=True)
   isbn = fields.Char(string="ISBN编号")
   author = fields.Char(string="作者")
   active = fields.Boolean(string="启用", default=True)
   parent_id = fields.Many2one(
       'library.book',
       string="父级图书",
       ondelete='cascade'
   )

2. 临时模型(TransientModel)—— 临时数据助手

临时模型专为临时数据设计,用于完成特定任务后自动清理。这类模型会将数据存储在数据库中,但自带自动销毁机制——系统会自动清理旧记录,避免数据库冗余。它们非常适合向导、临时计算和用户交互表单。

适用场景:向导表单、临时报表、数据导入/导出助手、无需永久存储的用户偏好弹窗。

# -*- coding: utf-8 -*-
class BookReportWizard(models.TransientModel):
   _name = 'library.book.report.wizard'  # 模型唯一名称
   _description = '图书报表生成向导'  # 展示名称
   _table = 'library_book_report_wizard'  # 自定义表名(可选)
   _rec_name = 'name'  # 界面中展示的字段
   _order = 'id desc'  # 默认排序
   _inherit = []  # 经典继承(向导中极少使用)
   _inherits = {}  # 委托继承(不推荐在此使用)
   _abstract = False  # 非抽象模型
   _transient = True  # 标记为临时模型
   _auto = True  # 自动创建表
   _register = True  # 在 ORM 中注册
   _transient_max_count = 1000  # 保留的最大记录数
   _transient_max_hours = 1.0  # 自动删除超过 X 小时的记录
   _parent_name = None  # 向导中不使用
   _parent_store = False  # 无层级结构
   _active_name = 'active'  # 可选的归档支持
   _check_company_auto = False  # 通常无需配置
   _allow_sudo_commands = True  # 允许 sudo 操作
   _rec_names_search = ['name']  # 搜索字段
   # SQL 相关(临时模型不使用)
   _table_query = None
   _depends = {}
   # 字段定义
   name = fields.Char(string="向导名称")
   date_from = fields.Date(string="开始日期")
   date_to = fields.Date(string="结束日期")
   active = fields.Boolean(string="启用", default=True)

3. 抽象模型(AbstractModel)—— 可复用的蓝图模板

抽象模型是实现代码高效复用的核心。它们不会创建独立的数据库表,而是作为其他模型继承的基础结构。你可以将其理解为可复用组件,提供共享的字段、方法和行为,让多个模型无需重复编写代码即可使用相同功能。

适用场景:邮件线程、网站发布功能等通用逻辑,或多个模型需要实现的共享行为。

# -*- coding: utf-8 -*-
class TimestampMixin(models.AbstractModel):
   _name = 'timestamp.mixin'  # 唯一技术名称
   _description = '时间戳混合模型(通用日期字段)'  # 展示名称
   _table = None  # 抽象模型不创建表
   _rec_name = None  # 抽象模型通常无需配置
   _order = None  # 无默认排序(不直接使用)
   _inherit = []  # 可继承其他混合模型(如需)
   _inherits = {}  # 委托继承(抽象模型极少使用)
   _abstract = True  # 标记为抽象模型
   _transient = False  # 非临时模型
   _auto = False  # 不创建数据库表
   _register = True  # 注册模型以便被继承
   _parent_name = None  # 无层级关系
   _parent_store = False  # 无树形结构优化
   _active_name = None  # 无归档概念
   _check_company_auto = False  # 混合模型无需配置
   _allow_sudo_commands = True  # 默认允许 sudo 操作
   _rec_names_search = []  # 不使用
   # SQL 相关(不适用)
   _table_query = None
   _depends = {}
   # 通用可复用字段
   created_on = fields.Datetime(
       string="创建时间",
       default=fields.Datetime.now
   )
   updated_on = fields.Datetime(
       string="最后更新时间"
   )

模型属性完整详解

了解模型类型后,我们来学习全套模型属性,这些属性让你精准控制模型的行为:

核心标识属性

  • _name (字符串):模型的唯一标识符,采用点分隔格式。这是模型的唯一标识,在整个 Odoo 系统中必须唯一。示例:'sale.order'、'res.partner'、'product.template'。
  • _description (字符串 | None):模型的可读名称,显示在用户界面、菜单和错误提示中。虽为可选配置,但对用户体验至关重要。示例:'销售订单'、'客户'、'产品模板'。
  • _module (字符串 | None):标识该模型所属的 Odoo 模块,用于管理模块依赖和结构。通常由框架自动设置。
  • _custom (布尔值):仅当模型通过 Odoo 工作室或自定义开发创建时,设为 True。用于区分 Odoo 核心模型和自定义扩展模型。

数据库与表管理

  • _auto (布尔值):控制 Odoo 是否自动为模型创建数据库表。如需手动创建表或使用数据库视图,设为 False。抽象模型默认值为 True。
  • _table (字符串):指定数据库中使用的精确 SQL 表名。未设置时,Odoo 会自动将模型名称中的点替换为下划线生成表名。
  • _table_query (SQL 语句 | 字符串 | None):将模型内容定义为 SQL 表达式,本质是创建数据库视图而非普通表。非常适合复杂报表模型。
  • _table_objects (字典):高级属性,用于定义与模型关联的 SQL/表对象,适用于复杂数据库操作和性能优化。

模型行为标记

  • _register (布尔值):控制模型是否注册到 Odoo 模型注册表并被框架识别。无需实例化的工具类可设为 False。
  • _abstract (布尔值):标记模型为抽象模型。抽象模型不创建数据库表,仅用于被其他模型继承,实现功能共享。
  • _transient (布尔值):标记模型为临时模型,其记录会在一段时间后被系统自动清理。适用于临时数据和向导。

继承与组合

  • _inherit (字符串 | 字符串列表 | 元组):定义 Python 风格的继承。设置了 _name 时,代表继承的父模型;未设置 _name 时,直接扩展现有的模型,添加新字段和方法。
  • _inherits (冻结字典):通过字典(父模型名称: 外键字段名)实现基于组合的继承。新模型可直接访问父模型的所有字段,但数据存储在关联的记录中。
  • _inherit_children (有序集合):框架自动维护的子模型集合,记录继承自当前模型的所有子模型。用于框架内部的继承解析。

用户界面与展示

  • _rec_name (字符串 | None):在选择列表、多对一字段和面包屑导航中展示记录名称的字段。若存在 name 字段,默认使用该字段;否则使用第一个字段。
  • _rec_names_search (字符串列表 | None):用户在多对一字段或全局搜索中输入关键词时,用于检索的字段列表。支持多字段搜索,提升用户体验。
  • _order (字符串):未指定排序规则时,记录的默认排序方式。使用 SQL 的 ORDER BY 语法。示例:'name asc'、'create_date desc, name'。
  • _fold_name (字符串):用于判断看板视图分组是否折叠的字段名。通常是布尔字段,控制看板列的展开/折叠状态。

层级结构

  • _parent_name (字符串):创建同模型记录父子关系的多对一字段。支持组织结构图、分类树等层级结构。
  • _parent_store (布尔值):通过计算 parent_path 字段,启用层级数据的优化存储。大幅提升大型层级数据集的 child_of 和 parent_of 域操作性能。

记录归档管理

  • _active_name (字符串 | None):自动设置为 active 或 x_active,标识用于记录归档/取消归档的字段。启用的记录显示在普通视图中,归档记录隐藏但不会被删除。

本地化与翻译

  • _translate (布尔值):控制模型字段是否包含在翻译导出文件中。该属性为遗留功能,未来版本可能会被废弃。

安全与权限控制

  • _check_company_auto (布尔值):自动对标记了 check_company=True 的关联字段验证公司一致性。防止多公司环境下的数据泄露问题。
  • _allow_sudo_commands (布尔值):控制使用 sudo() 或 with_user() 时,一对多、多对多操作是否可指向该模型。安全敏感模型应设为 False,防止权限提升攻击。

高级性能优化

  • _depends (冻结字典):为 SQL 视图驱动的模型定义依赖关系,指定触发更新的模型字段。格式:{模型名称: 字段名称列表}。用于缓存失效和数据库同步。

Odoo 19 中的扩展继承

class SaleOrder(models.Model):
    """
    该类扩展现有的 `sale.order` 模型,添加自定义测试字段
    技术说明:
        - 使用经典继承(_inherit)
        - 不创建新模型,仅扩展现有模型
    """
    _inherit = 'sale.order'  # 扩展现有的模型
    test_field = fields.Char(
        string="测试字段",
        help="这是一个测试字段。",
    )

Odoo 19 中的委托继承

class LibraryBook(models.Model):
    """
    该模型演示通过 `_inherits` 实现与 `product.template` 的委托继承
    核心概念:
        - `_inherits` 通过多对一字段关联模型
        - 可直接访问父模型的字段
        - 数据存储在多张表中
    """
    _name = 'library.book'
    _description = '关联产品模板的图书馆图书'
    _inherits = {
        'product.template': 'product_tmpl_id'
    }
    product_tmpl_id = fields.Many2one(
        'product.template',
        string="关联产品",
        required=True,
        ondelete='cascade',
        help="将图书与产品模板记录关联。"
    )
    author = fields.Char(
        string="作者",
        help="图书作者姓名。",
        required=True,
        index=True,
    )
    isbn = fields.Char(
        string="ISBN编号",
        help="图书唯一标识。",
        copy=False,
        index=True,
    )

经典继承示例

class Inheritance0(models.Model):
   _name = 'inheritance.0'
   _description = '基础继承模型'
   name = fields.Char()
   def call(self):
       return self.check("模型 0")
   def check(self, s):
       return "这是 {} 记录 {}".format(s, self.name)

class Inheritance1(models.Model):
   _name = 'inheritance.1'
   _inherit = ['inheritance.0']
   _description = '扩展继承模型'
   def call(self):
       return self.check("模型 1")
总结


Odoo 19 技术教程:如何在 Odoo 19 中使用模型属性
中国 Odoo, 苏州远鼎 2026年4月20日
标签
存档