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

如何在用户下载ir_attachment后删除附件以保持数据库清洁?

解决方案

方法1:用定时任务清理临时附件

适合无需立即删除的场景,通过标记临时附件,后台定期自动清理。

步骤1:扩展ir.attachment添加临时标记字段

from odoo import models, fields

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

    is_temp = fields.Boolean(string='临时附件', default=False)

步骤2:创建附件时标记为临时

修改你的创建代码,添加临时标记:

attachment = self.env["ir.attachment"].create({
    'name': file_name,
    'type': 'binary',
    'datas': base64.b64encode(zip_data).decode(),
    'res_model': self._name,
    'store_fname': file_name,
    'mimetype': 'application/zip',
    'is_temp': True,  # 标记为临时附件
})
# 后续下载代码保持不变

步骤3:创建定时任务自动清理

进入Odoo后台【设置】→【技术】→【自动化】→【定时动作】,新建定时任务:

  • 模型:ir.attachment
  • 执行动作:执行Python代码
  • 代码内容:
from datetime import timedelta
self.search([
    ('is_temp', '=', True),
    ('create_date', '<', (fields.Datetime.now() - timedelta(hours=1)))
]).unlink()
  • 执行频率:根据需求设置(如每小时一次)

方法2:前端下载完成后立即删除附件

实现下载完成后即时清理,需配合前端JS和自定义控制器。

步骤1:创建删除附件的控制器

from odoo import http
from odoo.http import request

class TempAttachmentController(http.Controller):
    @http.route('/web/temp_attachment/delete', type='json', auth='user')
    def delete_temp_attachment(self, attachment_id):
        attachment = request.env['ir.attachment'].browse(int(attachment_id))
        if attachment.exists():
            attachment.unlink()
        return {'success': True}

步骤2:修改返回动作,触发前端逻辑

替换原act_url返回,改用客户端动作:

return {
    'type': 'ir.actions.client',
    'tag': 'download_and_delete_attachment',
    'params': {
        'attachment_id': attachment.id,
        'download_url': f'/web/content/{attachment.id}?download=true',
    }
}

步骤3:添加前端JS处理下载与删除

在模块static/src/js目录下创建download_handler.js:

odoo.define('your_module.download_handler', function(require) {
    'use strict';

    var core = require('web.core');
    var ActionManager = require('web.ActionManager');

    ActionManager.include({
        execute_action: function(action, options) {
            if (action.tag === 'download_and_delete_attachment') {
                var params = action.params;
                // 创建隐藏a标签触发下载
                var a = document.createElement('a');
                a.href = params.download_url;
                a.download = '';
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                
                // 轮询检查下载状态,完成后调用删除接口
                var interval = setInterval(function() {
                    var xhr = new XMLHttpRequest();
                    xhr.open('HEAD', params.download_url, false);
                    try {
                        xhr.send();
                        if (xhr.status === 404) {
                            clearInterval(interval);
                            odoo.rpc('/web/temp_attachment/delete', {attachment_id: params.attachment_id});
                        }
                    } catch(e) {
                        clearInterval(interval);
                    }
                }, 1000);
                
                return Promise.resolve();
            }
            return this._super(action, options);
        }
    });

    return {};
});

在模块views/assets.xml中引入该JS:

<odoo>
    <template id="assets_backend" name="your_module assets" inherit_id="web.assets_backend">
        <xpath expr="." position="inside">
            <script type="text/javascript" src="/your_module/static/src/js/download_handler.js"></script>
        </xpath>
    </template>
</odoo>

方法3:直接返回二进制数据,不创建ir.attachment

从根源避免冗余数据,无需删除操作,是最优解。

步骤1:创建返回文件流的控制器

from odoo import http
from odoo.http import request
import base64

class DownloadController(http.Controller):
    @http.route('/web/download/zip_file', type='http', auth='user')
    def download_zip(self, model, res_id):
        # 根据model和res_id获取数据生成zip_data(替换为你的生成逻辑)
        record = request.env[model].browse(int(res_id))
        zip_data = record.generate_zip_data()
        
        # 返回二进制响应
        return request.make_response(
            base64.b64decode(base64.b64encode(zip_data).decode()),
            headers=[
                ('Content-Type', 'application/zip'),
                ('Content-Disposition', f'attachment; filename="{file_name}"'),
            ]
        )

步骤2:修改调用逻辑,直接跳转控制器URL

return {
    'type': 'ir.actions.act_url',
    'url': f'/web/download/zip_file?model={self._name}&res_id={self.id}',
    'target': 'self',
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 03:37:15