Odoo 15:依赖Many2One搜索计数的非存储计算字段搜索问题
问题说明
我需要展示拥有多个BoM的特定产品视图,已创建计算字段ppa_multi_bom标记符合条件的记录,但在实现搜索筛选时遇到问题——代码返回空数据列表,怀疑是记录ID获取和列表追加的方式有误,附上代码求助:
class products_ppa_bom_check(models.Model): _inherit = ['product.template'] ppa_multi_bom = fields.Selection([ ('true', 'True'), ('false', 'False'), ('na', 'Not Applicable')], string="PPA Multi BOM Check", compute='_compute_ppa_multi_bom', search='_search_ppa_multi_bom') def _compute_ppa_multi_bom(self): for record in self: count = record.env['mrp.bom'].search_count(['|', ('product_tmpl_id', '=', record.id), ('byproduct_ids.product_id.product_tmpl_id', '=', record.id)]) if (count > 1) and ('PPA' in str(record.default_code)): record.ppa_multi_bom = 'true' elif (count == 1) and ('PPA' in str(record.default_code)): record.ppa_multi_bom = 'false' else: record.ppa_multi_bom = 'na' def _search_ppa_multi_bom(self, operator, value): ids = [] for record in self: count = record.env['mrp.bom'].search_count(['|', ('product_tmpl_id', '=', record.id), ('byproduct_ids.product_id.product_tmpl_id', '=', record.id)]) if (count > 1) and ('PPA' in str(record.default_code)): ids = ids.append(record.id) return[('id', 'in', ids)]
问题排查与修复
核心问题1:列表追加错误
ids = ids.append(record.id)是错误写法——list.append()是原地修改列表,没有返回值,执行后ids会被赋值为None,最终搜索条件('id', 'in', None)完全无效。正确写法是直接调用ids.append(record.id)。
核心问题2:搜索逻辑错误
搜索方法中遍历self是错误的:self在搜索上下文里并非全量产品记录集,无法覆盖所有符合条件的数据。同时当前代码完全忽略了传入的operator和value参数,不管用户选的是true/false/na,都只返回固定条件的记录,逻辑完全不符合需求。
优化后的完整代码
from collections import defaultdict class products_ppa_bom_check(models.Model): _inherit = ['product.template'] ppa_multi_bom = fields.Selection([ ('true', 'True'), ('false', 'False'), ('na', 'Not Applicable')], string="PPA Multi BOM Check", compute='_compute_ppa_multi_bom', search='_search_ppa_multi_bom') def _compute_ppa_multi_bom(self): # 批量统计BOM数量,减少数据库查询次数 bom_counts = defaultdict(int) # 一次性查询所有关联当前产品的BOM记录 bom_records = self.env['mrp.bom'].search([ '|', ('product_tmpl_id', 'in', self.ids), ('byproduct_ids.product_id.product_tmpl_id', 'in', self.ids) ]) # 统计每个产品模板的BOM数量 for bom in bom_records: # 统计主产品关联的BOM if bom.product_tmpl_id: bom_counts[bom.product_tmpl_id.id] += 1 # 统计副产品关联的BOM for byproduct in bom.byproduct_ids: tmpl_id = byproduct.product_id.product_tmpl_id.id bom_counts[tmpl_id] += 1 for record in self: count = bom_counts.get(record.id, 0) default_code = str(record.default_code) if record.default_code else '' if 'PPA' in default_code: record.ppa_multi_bom = 'true' if count > 1 else 'false' if count == 1 else 'na' else: record.ppa_multi_bom = 'na' def _search_ppa_multi_bom(self, operator, value): # 构造子查询统计每个产品的BOM总数 bom_count_subquery = self.env['mrp.bom']._search( ['|', ('product_tmpl_id', '=', self.env['product.template'].id), ('byproduct_ids.product_id.product_tmpl_id', '=', self.env['product.template'].id)], count=True ) domain = [] if value == 'true': # 筛选PPA开头且BOM数量>1的产品 domain = [('default_code', 'ilike', 'PPA'), (bom_count_subquery, '>', 1)] elif value == 'false': # 筛选PPA开头且BOM数量=1的产品 domain = [('default_code', 'ilike', 'PPA'), (bom_count_subquery, '=', 1)] elif value == 'na': # 筛选非PPA开头或无BOM的产品 domain = ['|', ('default_code', 'not ilike', 'PPA'), (bom_count_subquery, '=', 0)] # 处理反向筛选(比如operator为!=的情况) if operator == '!=': return ['!'] + domain return domain
优化点说明
- 计算字段批量查询BOM记录,避免循环中多次调用
search_count,大幅提升性能。 - 搜索方法使用子查询统计BOM数量,无需遍历所有记录,效率更高且符合Odoo ORM规范。
- 完整支持
operator和value参数,能正确响应正向/反向筛选需求。
内容的提问来源于stack exchange,提问作者Josh Chan
相关产品推荐
相关产品推荐

