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

Odoo15开发:Controller实现附件Zip下载报KeyError问题

Odoo附件打包Zip下载功能KeyError报错问题修复

问题背景

需要实现将系统附件打包为Zip格式下载的功能,编写模型方法和Controller路由后运行异常,访问下载路由时触发报错。

相关代码截图

代码运行截图

模型层代码(attachment.py)

from odoo import api, fields, models, _
from odoo.odoo.exceptions import UserError


class IrAttachment(models.Model):
    _inherit = ["ir.attachment", "sale.order.line"]

    def download_product_attachments(self):
        attachment_id = self.datas
        if attachment_id:
            return {"type": "ir.actions.act_url",
                    "url": "/download_attachments?attachment_id={}".format(
                        ",".join([str(elem) for elem in attachment_id.ids])),
                    "target": "new",
                    "res_id": self.id,
                    }
        else:
            raise UserError("Photos were not found")

控制层代码(controllers/main.py)

class DownloadZipFile(http.Controller):
    @http.route("/download_attachments", type="http", auth="user", website=True)
    def download_attachments_product_routes(self, **data):
        """Method compose data with attachments and send for download."""
        attachments_ids = [int(x) for x in data["attachment_id"].split(',')]
        attachments_items = request.env["ir.attachment"].search([("id", "in", attachments_ids)])
        in_memory = BytesIO()
        zip_archive = ZipFile(in_memory, "w")
        for attachment in attachments_items:
            zip_archive.writestr(attachment.filename, base64.b64decode(attachment.image))
        zip_archive.close()
        res = http.send_file(in_memory, filename="attachments.zip", as_attachment=True)
        return res

报错信息

报错文件路径:/home/user/PycharmProjects/Odoo14/custom/first_model/controllers/main.py
报错位置:第32行download_attachments_product_routes方法内的attachments_ids = [int(x) for x in data["attachment_id"].split(',')]语句
错误信息:KeyError: 'attachment_id'

问题原因

代码存在4处核心错误,直接或间接导致报错:

  • 控制器参数接收逻辑不严谨:路由方法未显式声明attachment_id形参,也未做参数存在性校验,当访问路径未携带attachment_id查询参数时,直接从data字典取不存在的键就会触发KeyError。
  • 模型层继承逻辑错误:_inherit = ["ir.attachment", "sale.order.line"]属于错误的多模型继承写法,该需求仅需扩展ir.attachment模型,不需要继承销售订单行模型。
  • 模型层字段引用错误:self.datas是ir.attachment模型存储二进制内容的base64字段,不是关联记录集,不存在.ids属性,点击按钮时模型层就会抛出属性错误,无法生成正确的带参下载链接,间接导致跳转时参数丢失。
  • 控制层字段&导入缺失:ir.attachment模型的文件名字段为name、二进制内容字段为datas,代码中错误引用了不存在的filename、image字段;同时代码中用到的BytesIO、ZipFile、base64模块均未显式导入,就算解决KeyError也会触发后续的字段不存在、名称未定义报错。

修复后代码

修复后的attachment.py

from odoo import api, fields, models, _
from odoo.exceptions import UserError


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

    def download_product_attachments(self):
        if not self:
            raise UserError("Photos were not found")
        return {
            "type": "ir.actions.act_url",
            "url": "/download_attachments?attachment_id={}".format(",".join(map(str, self.ids))),
            "target": "new",
        }

修复后的controllers/main.py

import base64
from io import BytesIO
from zipfile import ZipFile
from odoo import http
from odoo.http import request


class DownloadZipFile(http.Controller):
    @http.route("/download_attachments", type="http", auth="user", website=True)
    def download_attachments_product_routes(self, attachment_id=None, **kwargs):
        """组装附件内容并返回Zip压缩包下载响应"""
        if not attachment_id:
            return request.not_found()
        attachments_ids = [int(x) for x in attachment_id.split(',')]
        # 加sudo避免附件权限不足导致读取失败
        attachments_items = request.env["ir.attachment"].sudo().search([("id", "in", attachments_ids)])
        in_memory = BytesIO()
        with ZipFile(in_memory, "w") as zip_archive:
            for attachment in attachments_items:
                # 文件名加ID前缀避免重名文件被覆盖
                file_name = f"{attachment.id}_{attachment.name}"
                file_content = base64.b64decode(attachment.datas or b'')
                zip_archive.writestr(file_name, file_content)
        # 将指针移到流开头,避免下载的压缩包损坏
        in_memory.seek(0)
        return http.send_file(in_memory, filename="attachments.zip", as_attachment=True)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:22:03