Odoo Journal Entry模块Excel导入报错,求助排查缺失变量
Odoo导入Excel数据到account.move.line时报错排查
问题背景
代码实现以下功能:
- 读取Excel文件的行数据
- 将每行数据分配到对应字段
- 逐行将数据存储到数据库
运行时触发AttributeError: 'NoneType' object has no attribute 'res_id'错误。
原代码
import json import os from openpyxl import load_workbook from odoo import models, fields, api from odoo.exceptions import ValidationError class AccountMoveInherit(models.Model): _inherit = 'account.move' def importar_action(self): # Cargar el archivo de Excel sin espacios en el nombre. ruta_modulo = os.path.dirname(os.path.abspath(__file__)) archivo_ruta = os.path.join(ruta_modulo, 'static', 'src', 'lineasdefacturas5.xlsx') workbook = load_workbook(archivo_ruta) # Seleccionar la hoja de origen ws_origen = workbook['Query1'] #obtenemos la longitud de las filas y columnas filas_origen = ws_origen.max_row columnas_origen = 8 for fila in range(2, filas_origen + 1): lista_valores = [None] * 8 numero = 0 for columna in range(1, columnas_origen + 1): valor_celda = ws_origen.cell(row=fila, column=columna).value lista_valores[numero] = valor_celda numero += 1 idFact = self.env['ir.model.data'].search([('name','=',lista_valores[1])]).res_id idProduct = self.env['product.template'].search([('name','=',lista_valores[2])]).id objeto = { 'id': lista_valores[0], 'move_id': idFact, 'product_id': idProduct, 'quantity': lista_valores[3], 'price_unit': lista_valores[4], 'company_currency_id': lista_valores[5], 'journal_id': lista_valores[6], 'account_id': lista_valores[7], } record = self.env['account.move.line'].create(objeto)
报错原因分析
- 空值访问错误:报错指向
idFact = self.env['ir.model.data'].search([('name','=',lista_valores[1])]).res_id,说明search未找到匹配记录,返回None,直接访问res_id触发NoneType属性错误。同理idProduct的获取逻辑也存在相同风险。 - 循环逻辑错误:获取
idFact和idProduct的代码写在列循环内部,会在读取每一列时重复执行搜索,完全冗余且影响效率。 - 手动指定ID风险:手动传入
id字段可能与Odoo自动生成的ID冲突,导致数据异常。
修正方案
1. 修正核心逻辑
for fila in range(2, filas_origen + 1): lista_valores = [None] * 8 numero = 0 for columna in range(1, columnas_origen + 1): valor_celda = ws_origen.cell(row=fila, column=columna).value lista_valores[numero] = valor_celda numero += 1 # 移到列循环外,避免重复执行 # 处理idFact:添加空值检查 ir_data_record = self.env['ir.model.data'].search([('name','=',lista_valores[1])], limit=1) idFact = ir_data_record.res_id if ir_data_record else False if not idFact: raise ValidationError(f"第{fila}行:未找到name为{lista_valores[1]}的ir.model.data记录") # 处理idProduct:添加空值检查 product_template_record = self.env['product.template'].search([('name','=',lista_valores[2])], limit=1) idProduct = product_template_record.id if product_template_record else False if not idProduct: raise ValidationError(f"第{fila}行:未找到name为{lista_valores[2]}的product.template记录") objeto = { 'move_id': idFact, 'product_id': idProduct, 'quantity': lista_valores[3], 'price_unit': lista_valores[4], 'company_currency_id': lista_valores[5], 'journal_id': lista_valores[6], 'account_id': lista_valores[7], } # 移除手动指定的id字段,由Odoo自动生成 record = self.env['account.move.line'].create(objeto)
2. 额外优化建议
- 批量创建提升性能:如果数据量较大,建议收集所有待创建对象到列表,最后一次性调用
create:records_to_create = [] for fila in range(2, filas_origen + 1): # ... 上述处理逻辑,生成objeto records_to_create.append(objeto) self.env['account.move.line'].create(records_to_create) - 数据校验:提前检查Excel中对应列的内容是否与系统中
ir.model.data和product.template的name字段完全匹配(注意大小写、空格)。
内容的提问来源于stack exchange,提问作者Erick Toledo
相关产品推荐
相关产品推荐

