函数执行报错:product.product(3,)不可JSON序列化,求技术解决
这个错误的核心原因很明确: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

