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

如何在Odoo 16中为one2many字段实现批量导入记录功能

Odoo 16 批量上传数据至One2many字段解决方案

核心逻辑

One2many字段本质是关联子模型数据,批量上传的核心是:读取上传文件(以Excel为例)的行数据,创建/关联子模型记录,再绑定到主模型的One2many字段。以下是具体实现步骤:

步骤1:定义模型结构(示例场景)

假设主模型为main.order,One2many字段关联子模型main.order.line,子模型包含产品、数量、单价字段:

# 主订单模型
class MainOrder(models.Model):
    _name = 'main.order'
    _description = '主订单'

    name = fields.Char('订单编号')
    order_line_ids = fields.One2many('main.order.line', 'order_id', '订单明细')

# 订单明细子模型
class MainOrderLine(models.Model):
    _name = 'main.order.line'
    _description = '订单明细'

    order_id = fields.Many2one('main.order', '主订单', required=True)
    product_id = fields.Many2one('product.product', '产品', required=True)
    quantity = fields.Float('数量', required=True)
    price = fields.Float('单价', required=True)

步骤2:添加上传按钮与处理逻辑

表单视图(XML)

在主订单表单中添加批量导入按钮:

<record id="view_main_order_form" model="ir.ui.view">
    <field name="name">main.order.form</field>
    <field name="model">main.order</field>
    <field name="arch" type="xml">
        <form>
            <header>
                <button name="action_upload_order_lines" string="批量导入明细" type="object" class="btn-primary"/>
            </header>
            <sheet>
                <group>
                    <field name="name"/>
                    <field name="order_line_ids" widget="one2many_list">
                        <tree editable="bottom">
                            <field name="product_id"/>
                            <field name="quantity"/>
                            <field name="price"/>
                        </tree>
                    </field>
                </group>
            </sheet>
        </form>
    </field>
</record>

上传逻辑(Python)

使用openpyxl读取Excel,需先在requirements.txt添加openpyxl并安装依赖:

from openpyxl import load_workbook
from io import BytesIO
import base64
from odoo.exceptions import UserError

class MainOrder(models.Model):
    _inherit = 'main.order'

    def action_upload_order_lines(self):
        # 弹出文件选择向导
        return {
            'name': '选择Excel文件',
            'type': 'ir.actions.act_window',
            'res_model': 'file.upload.wizard',
            'view_mode': 'form',
            'target': 'new',
            'context': {'default_order_id': self.id}
        }

# 文件上传向导模型
class FileUploadWizard(models.TransientModel):
    _name = 'file.upload.wizard'
    _description = '批量导入向导'

    order_id = fields.Many2one('main.order', '主订单', required=True)
    file = fields.Binary('Excel文件', required=True)
    file_name = fields.Char('文件名')

    def action_import(self):
        # 校验文件格式
        if not self.file_name.endswith('.xlsx'):
            raise UserError('仅支持.xlsx格式文件')
        
        # 读取二进制文件
        wb = load_workbook(filename=BytesIO(base64.b64decode(self.file)))
        ws = wb.active
        line_data = []

        # 跳过表头(假设第一行为表头)
        for row_num, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):
            product_name, quantity, price = row
            # 校验必填字段
            if not all([product_name, quantity, price]):
                raise UserError(f'第{row_num}行数据缺失,请检查')
            
            # 匹配产品(建议用产品编码替代名称,避免重复)
            product = self.env['product.product'].search([('name', '=', product_name)], limit=1)
            if not product:
                raise UserError(f'第{row_num}行产品【{product_name}】不存在')
            
            line_data.append({
                'order_id': self.order_id.id,
                'product_id': product.id,
                'quantity': quantity,
                'price': price
            })
        
        # 批量创建明细记录
        self.env['main.order.line'].create(line_data)
        # 刷新视图
        return {
            'type': 'ir.actions.client',
            'tag': 'reload'
        }

向导视图(XML)

<record id="view_file_upload_wizard_form" model="ir.ui.view">
    <field name="name">file.upload.wizard.form</field>
    <field name="model">file.upload.wizard</field>
    <field name="arch" type="xml">
        <form>
            <sheet>
                <group>
                    <field name="order_id" readonly="1"/>
                    <field name="file" filename="file_name"/>
                </group>
            </sheet>
            <footer>
                <button name="action_import" string="导入" type="object" class="btn-primary"/>
                <button string="取消" class="btn-secondary" special="cancel"/>
            </footer>
        </form>
    </field>
</record>

关键注意事项

  • 文件格式:Excel表头需与代码读取的字段顺序匹配,确保数量、单价为数字格式。
  • 数据匹配:关联记录(如产品)建议用唯一标识(如内部编码default_code)匹配,避免名称重复导致错误。
  • 性能优化:大数据量导入时,先收集所有数据到列表再批量create,减少数据库交互次数。
  • 错误处理:添加字段校验、异常捕获,用UserError明确提示用户问题所在。

测试流程

  1. 打开主订单表单,点击「批量导入明细」按钮。
  2. 选择准备好的Excel文件,点击「导入」。
  3. 订单明细的One2many字段将自动填充导入数据。

内容的提问来源于stack exchange,提问作者Nisarga Cm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 02:15:26