You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Odoo 15:如何让基模型树形视图显示所有继承类实例

Odoo经典继承下父模型树形视图显示子类实例的解决办法

问题本质

Odoo中经典继承(_inherit)的子类模型会生成独立的数据表,父模型(BASE)的默认查询只会返回自身表中的记录,无法自动包含子类(A、B)的实例,因此直接基于BASE创建的树形视图只能看到BASE自己的记录。

可行解决方案

方案1:创建代理模型统一查询

创建一个不存储数据的代理模型,通过重写search和read方法,合并A、B模型的记录并返回,以此作为树形视图的绑定模型。

示例代码:

from odoo import models, fields, api

class BaseProxy(models.Model):
    _name = 'base.proxy'
    _description = 'Base Model Proxy'
    _auto = False  # 不创建数据表

    # 定义与BASE、A、B一致的字段
    name = fields.Char(string='Name')
    # 其他继承自BASE的字段...

    @api.model
    def search(self, args, offset=0, limit=None, order=None, count=False):
        # 合并A和B模型的查询结果ID
        model_a_ids = self.env['model.a'].search(args).ids
        model_b_ids = self.env['model.b'].search(args).ids
        all_ids = model_a_ids + model_b_ids
        # 处理分页、排序等逻辑
        if order:
            # 根据需要实现排序逻辑,此处简化处理
            pass
        if offset:
            all_ids = all_ids[offset:]
        if limit:
            all_ids = all_ids[:limit]
        if count:
            return len(all_ids)
        # 返回代理模型的记录集,ID用原模型ID加前缀区分,避免冲突
        return self.browse([f'a_{id}' for id in model_a_ids] + [f'b_{id}' for id in model_b_ids])

    def read(self, fields=None, load='_classic_read'):
        res = []
        # 分别读取A和B模型的数据
        model_a_records = self.env['model.a'].browse([int(id.split('_')[1]) for id in self.ids if id.startswith('a_')])
        model_b_records = self.env['model.b'].browse([int(id.split('_')[1]) for id in self.ids if id.startswith('b_')])
        
        for rec in model_a_records:
            res.append(rec.read(fields)[0])
        for rec in model_b_records:
            res.append(rec.read(fields)[0])
        return res

之后为base.proxy模型创建树形视图,即可同时查看A和B的实例。

方案2:修改父模型的查询逻辑(不推荐)

直接重写BASE模型的search方法,让它查询子类数据并合并,但这种方式可能破坏Odoo的ORM逻辑,引发性能或兼容性问题,仅适用于简单场景。

示例代码:

class BaseModel(models.Model):
    _name = 'base.model'
    _description = 'Base Model'

    name = fields.Char(string='Name')

    @api.model
    def search(self, args, offset=0, limit=None, order=None, count=False):
        base_ids = super().search(args, offset=0, limit=None, order=order, count=False).ids
        model_a_ids = self.env['model.a'].search(args).ids
        model_b_ids = self.env['model.b'].search(args).ids
        all_ids = list(set(base_ids + model_a_ids + model_b_ids))
        # 处理分页、排序
        if order:
            # 需自行实现跨模型排序逻辑
            pass
        if offset:
            all_ids = all_ids[offset:]
        if limit:
            all_ids = all_ids[:limit]
        if count:
            return len(all_ids)
        return self.browse(all_ids)

注意:这种方式下,子类记录的ID可能与BASE模型ID冲突,且ORM的部分方法(如browse)可能无法正确处理子类数据,需谨慎使用。

方案3:使用抽象父模型+联合动作

如果BASE模型不需要单独创建实例,可将其设为抽象模型(_abstract = True),然后创建一个动作,通过domain的|运算符同时包含A和B模型的记录,再绑定到菜单。但Odoo视图仍需绑定到具体模型,因此可选择绑定其中一个模型,然后在动作中扩展查询范围:

示例动作代码:

<record id="action_base_all" model="ir.actions.act_window">
    <field name="name">All Base Instances</field>
    <field name="res_model">model.a</field>
    <field name="view_mode">tree</field>
    <field name="domain">[('id', 'in', (env['model.a'].search([]).ids + env['model.b'].search([]).ids))]</field>
</record>

这种方式的局限性是视图只能使用绑定模型的字段,若A和B有额外字段,需确保视图中使用的字段在两个模型中都存在。

内容的提问来源于stack exchange,提问作者Yugo Amaryl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 12:37:45