Odoo 模型继承与扩展机制解读

合理选择继承方式和错误处理机制,可以显著提高模块开发的效率和可靠性

本文参考:ORM API — Odoo 18.0 documentation

Odoo 模型继承与扩展机制解读

Odoo 提供了三种主要方式来扩展模型,每种方式都有特定的使用场景和机制:

  1. 传统继承(Classical Inheritance)
    新模型基于现有模型创建,继承原始模型的字段、方法和元信息,但原模型保持不变。
  2. 模型扩展(Extension)
    直接扩展现有模型,将新字段和方法添加到现有模型中。
  3. 委托继承(Delegation Inheritance)
    通过 _inherits 实现字段委托,但不继承方法。

1. 传统继承(Classical Inheritance)

特点

  • 创建一个全新的模型,基于现有模型。
  • 使用 _name 定义新模型名,使用 _inherit 指定父模型。
  • 可覆盖父模型的方法,同时继承其字段和其他方法。

代码示例

class Inheritance0(models.Model):
    _name = 'inheritance.0'
    _description = 'Inheritance Zero'

    name = fields.Char()

    def call(self):
        return self.check("model 0")

    def check(self, s):
        return "This is {} record {}".format(s, self.name)

class Inheritance1(models.Model):
    _name = 'inheritance.1'
    _inherit = 'inheritance.0'
    _description = 'Inheritance One'

    def call(self):
        return self.check("model 1")

使用示例

a = env['inheritance.0'].create({'name': 'A'})
b = env['inheritance.1'].create({'name': 'B'})

print(a.call())  # 输出: "This is model 0 record A"
print(b.call())  # 输出: "This is model 1 record B"

解读

  • Inheritance1 继承了 Inheritance0 的所有字段和方法。
  • Inheritance1 重写了 call 方法,但仍然可以调用 check 方法。

2. 模型扩展(Extension)

特点

  • 不创建新模型,而是直接扩展现有模型。
  • _inherit 指定扩展的模型,无需 _name。
  • 常用于添加新字段、方法或修改模型行为。

代码示例

class Extension0(models.Model):
    _name = 'extension.0'
    _description = 'Extension Zero'

    name = fields.Char(default="A")

class Extension1(models.Model):
    _inherit = 'extension.0'

    description = fields.Char(default="Extended")

使用示例

record = env['extension.0'].create({})
print(record.read()[0])
# 输出: {'name': "A", 'description': "Extended"}

解读

  • Extension1 向 extension.0 模型中添加了 description 字段。
  • 原始模型的字段和新字段均可用。

3. 委托继承(Delegation Inheritance)

特点

  • 使用 _inherits 将字段委托给其他模型。
  • 被委托的字段在父模型中可直接访问。
  • 不继承被委托模型的方法。

代码示例

class Screen(models.Model):
    _name = 'delegation.screen'
    size = fields.Float(string='Screen Size in inches')

class Keyboard(models.Model):
    _name = 'delegation.keyboard'
    layout = fields.Char(string='Layout')

class Laptop(models.Model):
    _name = 'delegation.laptop'
    _inherits = {
        'delegation.screen': 'screen_id',
        'delegation.keyboard': 'keyboard_id',
    }

    name = fields.Char(string='Name')
    maker = fields.Char(string='Maker')
    screen_id = fields.Many2one('delegation.screen', required=True, ondelete="cascade")
    keyboard_id = fields.Many2one('delegation.keyboard', required=True, ondelete="cascade")

使用示例

screen = env['delegation.screen'].create({'size': 13.0})
keyboard = env['delegation.keyboard'].create({'layout': 'QWERTY'})
laptop = env['delegation.laptop'].create({
    'screen_id': screen.id,
    'keyboard_id': keyboard.id,
})

print(laptop.size)      # 输出: 13.0
print(laptop.layout)    # 输出: "QWERTY"

laptop.write({'size': 14.0})

解读

  • Laptop 模型通过 _inherits 委托字段到 Screen 和 Keyboard。
  • Laptop 可以直接访问 Screen 和 Keyboard 的字段值,但无法继承它们的方法。

4.模型扩展委托继承的区别


区别总结

维度模型扩展委托继承
作用对象直接修改目标模型将字段委托到其他模型
字段继承可新增字段或修改现有字段通过外键关系访问委托模型的字段
方法继承支持重写目标模型的方法不继承委托模型的方法
数据库结构不创建新表,直接修改原表创建新表并通过 Many2one 外键关联委托模型
对原模型的影响会影响原模型的所有实例对原模型无直接影响
适用场景扩展现有模型的功能(如添加字段或自定义行为)将其他模型的字段组合到新模型中(如表示“包含”关系的场景)

总结类比

  • 模型扩展类似于“在现有房子上加建一层”。
  • 委托继承类似于“在新房子中安装了现成的家具”,可以用,但不改造家具本身。

5. 选择建议

  • 选择模型扩展:
    • 需要在现有模型中增加或重写字段、方法时。
    • 修改后的功能需要作用于整个系统的相关模块时。
    • 对模型的需求较为简单。
  • 选择委托继承:
    • 当前模型需要“组合”其他模型的字段,但原模型不能修改时。
    • 需要更高灵活性且对其他模型无侵入式影响时。
    • 适合表示“有一个”关系(has-a)的场景,例如:笔记本电脑“有一个”屏幕,而不是“是一个”屏幕。



6.字段的增量定义

特点

  • 可以通过在子类中重新定义字段来扩展其属性。
  • 必须保持字段类型一致。

代码示例

class First(models.Model):
    _name = 'foo'
    state = fields.Selection([('draft', 'Draft'), ('done', 'Done')], required=True)

class Second(models.Model):
    _inherit = 'foo'
    state = fields.Selection(help="Blah blah blah")

解读

  • Second 扩展了 state 字段,为其添加了提示信息(help 属性)。

7.错误处理

常见 Odoo 异常类型

异常类型描述示例
UserError用户操作无意义时抛出,类似 HTTP 400。提交状态不匹配的数据。
RedirectWarning显示警告信息的同时,可重定向用户到某操作。操作需用户手动确认时。
AccessDenied登录密码错误。尝试使用错误的密码登录。
AccessError访问权限错误。访问用户无权限查看的记录。
CacheMiss缓存中缺少值。访问已被刷新缓存的字段值。
MissingError记录不存在。操作已删除的记录。
ValidationError违反约束。创建重复登录名的用户。

8.总结

Odoo 的模型继承机制提供了灵活的扩展能力:

  • 传统继承:用于创建基于现有模型的新模型。
  • 模型扩展:用于修改或增强现有模型。
  • 委托继承:用于将字段委托到其他模型,实现“组合而非继承”。

合理选择继承方式和错误处理机制,可以显著提高模块开发的效率和可靠性。

徐朋朋 2024年11月23日
分析这篇文章

存档
登录 留下评论
odoo-ORM2
ORM API