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

函数执行报错:product.product(3,)不可JSON序列化,求技术解决

解决TypeError: product.product(3,) is not JSON serializable问题

这个错误的核心原因很明确:JSON序列化器无法处理Odoo的product.product记录集对象——JSON只支持原生数据类型(字符串、数字、列表、字典等),而Odoo的ORM对象不属于这个范畴。结合你的代码和错误信息,我梳理了几个可能的问题点和对应的解决办法:

1. 检查SQL查询返回的字段类型

虽然你用self.cr.execute直接执行SQL查询,返回的fetchall()结果理论上都是数据库原生类型(整数、字符串、日期等),但如果查询的字段是关联字段(比如inv.maitre_ouvrage是many2one类型),报表引擎在处理时可能会尝试将其转换成ORM对象,从而触发序列化错误。

解决办法:
如果需要显示关联对象的名称而非ID,修改SQL查询,直接关联到对应的表查询出名称。比如假设maitre_ouvrage关联的是res.partner表:

def _get_invoice_lines(self):
    # 使用JOIN语法替代隐式关联,更清晰且避免歧义
    query = """
        SELECT inv.number, l.price_subtotal_taxed, l.name, rp.name AS maitre_ouvrage_name,
               m.type_paiement, m.ref, m.date
        FROM product_product p
        JOIN account_invoice_line l ON p.id = l.product_id
        JOIN account_invoice inv ON inv.id = l.invoice_id
        JOIN account_move m ON m.invoice_id = inv.id
        JOIN res.partner rp ON inv.maitre_ouvrage = rp.id  -- 关联到伙伴表查询名称
        WHERE m.type_paiement IS NOT NULL
          AND inv.journal_id = 1
          AND m.type_paiement = %s
          AND inv.date_invoice = %s
          AND p.id = %s
    """
    # 使用参数化查询,避免SQL注入和类型错误
    self.cr.execute(query, (
        self.datas['type_paiement'],
        self.datas['date_invoice'],
        self.datas['product_id'].id if self.datas['product_id'] else None,
    ))
    return self.cr.fetchall()

2. 修复SQL拼接的潜在问题

你当前的代码使用字符串拼接来构建SQL语句,这不仅存在SQL注入风险,还可能因为变量类型处理不当导致意外问题。比如如果self.datas['product_id']是多记录的记录集,self.datas['product_id'].id会返回一个列表,直接拼到SQL里会引发语法错误,甚至可能传递对象到序列化流程中。

解决办法:
始终使用参数化查询(如上面的代码所示),让数据库驱动自动处理参数类型转换,同时确保product_id的ID被正确提取:

  • 如果self.datas['product_id']是单记录集:self.datas['product_id'].id可以正确获取整数ID
  • 如果支持多选产品,需要调整查询为IN语句:
def _get_invoice_lines(self):
    query = """
        SELECT inv.number, l.price_subtotal_taxed, l.name, rp.name AS maitre_ouvrage_name,
               m.type_paiement, m.ref, m.date
        FROM product_product p
        JOIN account_invoice_line l ON p.id = l.product_id
        JOIN account_invoice inv ON inv.id = l.invoice_id
        JOIN account_move m ON m.invoice_id = inv.id
        JOIN res.partner rp ON inv.maitre_ouvrage = rp.id
        WHERE m.type_paiement IS NOT NULL
          AND inv.journal_id = 1
          AND m.type_paiement = %s
          AND inv.date_invoice = %s
    """
    params = [
        self.datas['type_paiement'],
        self.datas['date_invoice'],
    ]
    # 处理产品ID的多选情况
    if self.datas.get('product_id'):
        product_ids = self.datas['product_id'].ids
        query += " AND p.id IN %s"
        params.append(tuple(product_ids))
    else:
        # 如果没有选择产品,可添加默认条件或移除该过滤
        query += " AND p.id IS NOT NULL"
    
    self.cr.execute(query, tuple(params))
    return self.cr.fetchall()

3. 检查报表数据上下文

错误也可能来自报表引擎尝试序列化self.datas中的product_id对象(而不是你的函数返回结果)。比如如果报表模板直接引用了self.datas['product_id'],而没有将其转换为ID或名称,就会触发序列化错误。

解决办法:
在传递给报表的上下文或数据中,将ORM对象转换为原生类型:

  • 传递产品ID:self.datas['product_id'].id
  • 传递产品名称:self.datas['product_id'].name

额外建议

  • 避免直接使用字符串拼接构建SQL语句,参数化查询是更安全、更可靠的方式
  • 测试时可以打印self.cr.fetchall()的结果,确认所有返回值都是原生类型,没有ORM对象
  • 如果使用的是QWeb报表,确保模板中只使用可序列化的数据类型,不要直接引用ORM对象

内容的提问来源于stack exchange,提问作者Loloi Hind

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:35:37