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

Odoo 8中计算字段筛选失效问题排查

解决Odoo发票附件数量字段搜索报错问题

问题分析

你当前的搜索方法实现存在两个核心问题:

  • 效率低下:遍历所有发票并计算附件数量,数据量大时会严重拖慢系统
  • 逻辑缺陷:直接在search方法中调用compute字段,容易引发上下文冲突,且报错显示返回的ID列表处理不当,导致Odoo无法解析domain条件

修复方案

方案1:优化Search方法(无需store=True)

直接通过SQL关联查询获取符合条件的发票ID,避免遍历所有记录:

attachment_count = fields.Integer(string="QAF", compute='count_attachments', search='_search_att_count')

@api.one
def count_attachments(self):
    # 保留原计算逻辑,示例:
    self.attachment_count = self.env['ir.attachment'].search_count([
        ('res_model', '=', 'account.invoice'),
        ('res_id', '=', self.id)
    ])

def _search_att_count(self, operator, value):
    cr = self._cr
    model_name = self._name
    ids = []
    
    if operator == '=':
        # 查询附件数量等于指定值的发票
        cr.execute("""
            SELECT res_id FROM ir_attachment
            WHERE res_model = %s
            GROUP BY res_id
            HAVING COUNT(id) = %s
        """, (model_name, value))
        ids = [row[0] for row in cr.fetchall()]
        # 处理数量为0的情况:包含无任何附件的发票
        if value == 0:
            cr.execute("""
                SELECT id FROM account_invoice
                WHERE id NOT IN (
                    SELECT res_id FROM ir_attachment WHERE res_model = %s
                )
            """, (model_name,))
            ids += [row[0] for row in cr.fetchall()]
    elif operator == '>':
        # 查询附件数量大于指定值的发票
        cr.execute("""
            SELECT res_id FROM ir_attachment
            WHERE res_model = %s
            GROUP BY res_id
            HAVING COUNT(id) > %s
        """, (model_name, value))
        ids = [row[0] for row in cr.fetchall()]
    elif operator == '<':
        # 查询附件数量小于指定值的发票(包含无附件的)
        cr.execute("""
            SELECT id FROM account_invoice
            WHERE id NOT IN (
                SELECT res_id FROM ir_attachment WHERE res_model = %s
            ) OR id IN (
                SELECT res_id FROM ir_attachment WHERE res_model = %s
                GROUP BY res_id HAVING COUNT(id) < %s
            )
        """, (model_name, model_name, value))
        ids = [row[0] for row in cr.fetchall()]
    
    return [('id', 'in', ids)]

方案2:启用store=True并添加更新触发器(推荐)

如果需要频繁搜索,推荐将字段存储到数据库,同时添加附件变更时的更新逻辑:

1. 修改发票模型的字段定义

attachment_count = fields.Integer(
    string="QAF", 
    compute='_compute_attachment_count', 
    store=True
)

@api.depends('message_attachment_ids')
def _compute_attachment_count(self):
    for rec in self:
        rec.attachment_count = len(rec.message_attachment_ids)

2. 扩展ir.attachment模型,添加更新触发器

在你的模块中创建ir.attachment的继承类:

from openerp import models, api

class IrAttachment(models.Model):
    _inherit = 'ir.attachment'

    @api.model
    def create(self, vals):
        res = super(IrAttachment, self).create(vals)
        # 当附件属于发票时,更新对应发票的附件计数
        if vals.get('res_model') == 'account.invoice' and vals.get('res_id'):
            invoice = self.env['account.invoice'].browse(vals['res_id'])
            invoice._compute_attachment_count()
        return res

    def unlink(self):
        # 记录要删除的附件对应的发票ID
        invoice_ids = [att.res_id for att in self if att.res_model == 'account.invoice']
        res = super(IrAttachment, self).unlink()
        # 更新对应发票的附件计数
        if invoice_ids:
            self.env['account.invoice'].browse(invoice_ids)._compute_attachment_count()
        return res

错误原因说明

你原代码中self.search([])会获取所有发票记录集,遍历访问x.attachment_count会触发compute方法,不仅效率极低,而且在旧API的search方法上下文里,这种操作容易导致Odoo无法正确解析返回的domain条件,最终触发AssertionError。

内容的提问来源于stack exchange,提问作者odoo newbie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 15:55:33