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
相关产品推荐
相关产品推荐

