如何在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
相关产品推荐
相关产品推荐

