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

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

优化点说明

  1. 计算字段批量查询BOM记录,避免循环中多次调用search_count,大幅提升性能。
  2. 搜索方法使用子查询统计BOM数量,无需遍历所有记录,效率更高且符合Odoo ORM规范。
  3. 完整支持operator和value参数,能正确响应正向/反向筛选需求。

内容的提问来源于stack exchange,提问作者Josh Chan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 06:55:14