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

如何在Odoo中创建调用API获取动态PDF的下载按钮?

Odoo 动态PDF展示与下载实现方案

1. 模型层:加按钮写触发逻辑

先在你要加按钮的Odoo模型里,定义按钮和对应的触发函数,核心是调用API拿二进制PDF,再把数据传给控制器。

示例代码(替换成你的模型名):

from odoo import models, api
import requests

class YourModel(models.Model):
    _inherit = 'res.partner'  # 比如给客户模型加按钮,换成你需要的模型

    def action_get_dynamic_pdf(self):
        # 调用你的API,按需传参数(比如当前记录ID)
        api_url = "https://your-api-domain.com/get-dynamic-pdf"
        response = requests.get(api_url, params={"record_id": self.id})
        response.raise_for_status()  # 请求失败直接抛错

        # 把PDF数据和文件名存在session里,给控制器用
        self.env['ir.http'].session['dynamic_pdf_data'] = response.content
        self.env['ir.http'].session['pdf_filename'] = f"report_{self.name}.pdf"

        # 跳转到控制器路由,打开新页面展示PDF
        return {
            'type': 'ir.actions.act_url',
            'url': '/web/dynamic-pdf/show',
            'target': 'new',
        }

注意:确保Odoo环境装了requests库,没装的话用pip install requests搞定。

2. 控制器层:处理PDF预览和下载

写个自定义控制器,读取session里的PDF数据,生成支持预览、下载的响应。

在controllers/main.py里加:

from odoo import http
from odoo.http import request

class DynamicPDFController(http.Controller):
    @http.route('/web/dynamic-pdf/show', type='http', auth='user')
    def show_pdf(self):
        pdf_data = request.session.get('dynamic_pdf_data')
        filename = request.session.get('pdf_filename', 'dynamic.pdf')

        if not pdf_data:
            return request.not_found("PDF数据不存在或已过期")

        # 生成预览响应,浏览器直接打开PDF
        headers = [
            ('Content-Type', 'application/pdf'),
            ('Content-Disposition', f'inline; filename="{filename}"'),
            ('Content-Length', str(len(pdf_data))),
        ]
        # 返回后清理session数据,避免占内存
        del request.session['dynamic_pdf_data']
        return request.make_response(pdf_data, headers=headers)

    @http.route('/web/dynamic-pdf/download', type='http', auth='user')
    def download_pdf(self):
        pdf_data = request.session.get('dynamic_pdf_data')
        filename = request.session.get('pdf_filename', 'dynamic.pdf')

        if not pdf_data:
            return request.not_found("PDF数据不存在或已过期")

        # 生成下载响应,触发文件保存
        headers = [
            ('Content-Type', 'application/pdf'),
            ('Content-Disposition', f'attachment; filename="{filename}"'),
            ('Content-Length', str(len(pdf_data))),
        ]
        del request.session['dynamic_pdf_data']
        return request.make_response(pdf_data, headers=headers)

3. 优化:弹窗带下载按钮的预览页面(可选)

不想直接跳新页面的话,可以做个Odoo弹窗,里面嵌PDF预览+下载按钮。

在views/templates.xml里加模板:

<odoo>
    <template id="dynamic_pdf_preview" name="Dynamic PDF Preview">
        <t t-call="web.layout">
            <div class="container mt-4">
                <div class="d-flex justify-content-between mb-3">
                    <h4>动态PDF预览</h4>
                    <a t-attf-href="/web/dynamic-pdf/download" class="btn btn-primary">下载PDF</a>
                </div>
                <iframe src="/web/dynamic-pdf/show" width="100%" height="700px" frameborder="0"></iframe>
            </div>
        </t>
    </template>
</odoo>

然后修改模型里的action_get_dynamic_pdf,改成打开这个弹窗:

return {
    'type': 'ir.actions.act_window',
    'name': '动态PDF预览',
    'res_model': 'ir.ui.view',
    'view_mode': 'form',
    'view_id': self.env.ref('your_module_name.dynamic_pdf_preview').id,
    'target': 'new',
}

4. 视图层:给模型加按钮

最后在对应模型的表单视图里,把按钮加进去,比如加在头部:

<odoo>
    <record id="partner_form_inherit_pdf_btn" model="ir.ui.view">
        <field name="name">res.partner.form.inherit.pdf.btn</field>
        <field name="model">res.partner</field>
        <field name="inherit_id" ref="base.view_partner_form"/>
        <field name="arch" type="xml">
            <xpath expr="//header" position="inside">
                <button name="action_get_dynamic_pdf" string="获取动态PDF" type="object" class="btn-primary"/>
            </xpath>
        </field>
    </record>
</odoo>

安全注意点

  • API认证:如果你的API需要密钥或token,在requests调用里加headers={"Authorization": "Bearer 你的token"}。
  • 权限控制:控制器用auth='user'确保只有登录用户能访问,要是需要更细的权限,在函数里加self.env.user.has_group('your_group_id')判断。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 18:35:11