InvenTree 报告模板(Report Templates)实战指南:从模板选项到多条目合并渲染
2026/9/17 20:32:01 网站建设 项目流程

InvenTree 报告模板(Report Templates)实战指南:从模板选项到多条目合并渲染

【免费下载链接】InvenTreeOpen Source Inventory Management System项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree

报告模板(Report Templates)是 InvenTree 生成正式 PDF 文档的核心机制,可用于输出订单报告、装箱单(Packing List)、测试报告等,并针对数据库中的单个条目(或条目列表)进行渲染。本文以 报告模板官方文档 为主体,结合 report 应用源码 展开讲解:你将掌握报告模板的核心选项(页面大小、横向、合并)、如何在 Web 界面生成报告、如何利用instances上下文将多个条目合并到单份 PDF,以及模板渲染背后的安全防护机制。

报告模板概览

报告模板与 InvenTree 其他模板(如标签模板)一样,使用HTML / CSSDjango 模板语言混合编写,并由WeasyPrint引擎渲染为 PDF 文件。官方文档对此给出了三个延伸阅读入口,均值得通读:

  • 模板总览(创建与管理模板)
  • WeasyPrint 渲染引擎与 Django 模板语言
  • 模板可用的上下文变量

从源码结构看,报告相关功能集中在src/backend/InvenTree/report/目录:models.py定义了ReportTemplateLabelTemplateReportSnippetReportAsset四个核心模型;helpers.py提供页面尺寸、模型类型解析与 base64 资源编码等辅助函数;fetcher.py实现了带安全限制的 WeasyPrint URL 抓取器。

模板与模型类型的绑定

每个模板都绑定一个 "Model Type"(目标模型类型),它决定了渲染时模板可获得的数据。模型类型字段在 models.py 中通过report.validators.validate_report_model_type校验,可用的模型类型由 helpers.py 中的report_model_options()动态收集——凡是继承了InvenTreeReportMixin的模型均可作为报告目标。常见的包括 Part(零件)、StockItem(库存条目)、StockLocation(库存位置)、Build Order(制造工单)、Sales Order(销售订单)、Purchase Order(采购订单)等,完整列表与各自可用的上下文变量见 上下文变量文档。

报告模板的核心选项

在模板通用的基础选项(名称、描述、修订号、启用状态、附加到模型、文件名模式、模板过滤器等,详见 创建模板)之外,每个报告模板还有三个专属选项,源码中对应ReportTemplate模型的三个字段(见 models.py):

Page Size(页面大小)

控制渲染 PDF 时使用的页面尺寸,例如A4Letter。新建模板时该值默认为全局设置中的默认页面大小(REPORT_DEFAULT_PAGE_SIZE,见 helpers.py)。

可选的页面尺寸在report_page_size_options()中定义,共四种:A4A3LegalLetter(见 helpers.py),其物理尺寸映射为:

页面代码尺寸(mm)
A4210 × 297
A3297 × 420
Legal215.9 × 355.6
Letter215.9 × 279.4

注意:自定义报告模板并不强制使用该选项——它只是通过上下文变量提供给模板,是否在 CSS 的@page规则中引用由模板作者自行决定。内置模板则会使用它,例如 inventree_report_base.html 中的size: {{ page_size }};即取自该上下文变量。

Landscape(横向)

布尔开关。启用后报告以横向(landscape)方向渲染,否则为默认的纵向(portrait)。从 models.py 的get_report_size()可以看到,横向会拼接为page_size + ' landscape'字符串,例如A4 landscape,直接交给 WeasyPrint 的 CSS@page规则使用。

Merge(合并)

布尔开关。启用后,所有选中的条目会合并进同一份报告文档,而不是每个条目单独生成一份。这是多条目打印场景中最常用的功能,下文专门展开。

这三个选项的值会以page_sizelandscapemerge三个上下文变量的形式注入模板(对应源码中的ReportContextExtension,见 models.py 与get_report_context()),模板内可直接通过{{ page_size }}{{ landscape }}{{ merge }}访问,详见 上下文变量文档中的 Report Context 一节。

生成报告:Web 界面操作流程

报告直接在 Web 界面、在目标条目的展示页面上生成。对一个或多个条目生成报告的标准流程如下:

  1. 选中要打印的条目——既可以在表格中使用行复选框批量选择,也可以进入单个条目的详情页;
  2. 选择Print(打印)操作,并选择Print Report(打印报告)选项;
  3. 选择报告模板——只有已启用(enabled)、且与所选模型类型匹配、并通过模板过滤器校验的模板才会出现在可选列表中;
  4. 服务端生成报告——报告由服务器端渲染,生成的 PDF 文件可供下载。

注意:报告生成功能默认是关闭的,必须在全局设置(Reporting 组)中启用报告功能后才能使用。

源码视角的渲染链路

报告的实际渲染入口是ReportTemplate.print()(见 models.py)。其核心链路为:

  • 遍历选中的items列表,对每个实例调用get_context()组装上下文,或走合并分支组装instances上下文(见下文);
  • 调用render_as_string()将 Django 模板渲染为 HTML 字符串,再调用render()通过HTML(string=html, url_fetcher=InvenTreeURLFetcher()).write_pdf(pdf_forms=True)生成 PDF 字节流;
  • 所有单条报告输出最终由pypdfPdfWriter合并为一个 PDF 文件,并保存到数据库的DataOutput记录中供下载。

若设置了REPORT_DEBUG_MODE(调试模式),则不再走 PDF 渲染,而是把模板渲染为纯 HTML 字符串(输出文件扩展名也由.pdf改为.html),便于排查 HTML 结构问题——这正是模板总览中 Debug Mode 的底层实现。需要提醒的是,调试模式下@page属性(如页面尺寸)和服务器上的资源文件不会生效,因此它不适用于生成"好看的"文档。

合并报告(Merging Reports):多条目渲染到单份 PDF

默认情况下,对多个条目渲染报告时,每个条目会被单独渲染一份报告:模板被重复渲染多次,每次上下文里只有一个条目对象。如果需要把多个条目合并进同一份报告文档,只需启用模板的Merge选项:

上图是报告模板编辑界面中Merge选项的真实截图——注意其帮助文本:"Render a single report against selected items"(针对所选条目渲染单个报告)。

启用merge后,所有选中的条目会被统一放入instances上下文变量中(一个包含所有选中条目的列表),模板作者可以遍历该列表,把多个条目渲染到同一份文档里。

实例上下文(Instance Context)

当用单个模板渲染多个模型实例(例如多个 Part、多个 StockItem)时,每个被渲染的实例都有自己独立的上下文数据

  • 每个 "instance" 以上下文变量字典的形式提供给模板,可复用标准 Django 模板语法访问;
  • instances是所有这些字典组成的列表,模板中通过遍历instances逐个渲染;
  • 各模型类型可用的上下文变量见上下文变量文档;
  • 访问前缀提醒:在instances列表中访问每个条目的变量时,要加上instance.前缀(例如instance.part.name)。

合并上下文在源码中由print()的合并分支构造(见 models.py):先取全局基础上下文与报告上下文,再对每个实例单独调用instance.report_context()(并叠加插件注入的上下文)收集为item_contexts列表,最后整体合并为{**base_context, **report_context, 'instances': item_contexts},一次性渲染。

合并报告示例

以下是一个将多个 Part 打印到同一份报告中的模板示例:启用merge后,模板收到instances列表,遍历即可:

{% for instance in instances %} Part Name: {{ instance.part.name }} <br> IPN: {{ instance.part.IPN }} <br> Description: {{ instance.part.description }} <br> {% endfor %}

每个instance都是符合标准 Part 上下文结构 的变量字典。上下文变量文档中还给出了一个把选中零件渲染为表格的完整 HTML 示例(遍历instances输出 Name / Description 两列,见 context_variables.md)。

此外,合并上下文也支持按索引访问,例如instance.0.name直接取列表第一项。官方内置模板 inventree_stock_report_merge.html 就是一个现成的合并报告参考实现:它遍历instances,对每个条目渲染零件名称、描述、库存位置、序列号/数量,甚至循环输出item.installed_items中的安装子件列表。

报告模板的其他实用特性

文件名模式(Filename Pattern)

每个模板都有filename_pattern字段(默认值见 models.py,内置默认为report.pdf)。该模式同样使用 Django 模板语法渲染,且可访问生成报告时的完整上下文(并非精简子集),实际文件名由generate_filename()在渲染时生成(见 models.py)。例如针对 StockItem 的测试报告,可以用零件名与序列号拼接文件名:

文件名模式说明
{{ part.full_name }}-{{ serial }}.pdf零件全名 + 库存条目序列号
PurchaseOrder-{{ reference }}.pdf采购订单参考号(内置采购订单报告默认模式)
SalesOrder-{{ reference }}-{{ date }}.pdf销售订单参考号 + 当前日期

模板过滤器(Template Filters)

filters字段用于限制模板可对哪些条目生成报告,过滤目标取决于模板绑定的模型类型(字段定义与校验见 models.py 与 validators.py)。例如,一个StockItem报告如果只想对 "trackable"(可追踪)的库存条目生成,可以构造过滤条件,把可用条目限定为关联 Part 为可追踪的条目。若输入了无效过滤条件,界面会显示错误提示。

列表过滤使用__in语法,例如:

item__in=[1,2,3]

注意三点:列表必须用方括号[]包裹;列表项以逗号分隔;键名必须以双下划线结尾的__in结尾。

提醒:模板过滤属于进阶主题,需要一定的底层数据结构知识,配置时请务必确认字段名与查询语法正确。

修订号、启用状态与附件

  • Revision(修订号):每次保存模板自动递增,用于跟踪模板变更历史,只读不可直接编辑(源码见 models.py 的save()重写与revision字段定义)。渲染时可通过template_revision上下文变量访问;
  • Enabled(启用状态):布尔字段,关闭后模板从可用列表移除但不会从数据库删除;
  • Attach to Model(打印时附加到模型):启用后每次打印会把生成的报告副本作为文件附件自动保存到被渲染的模型实例上(前提是该模型类型支持附件),源码见handle_attachment()(models.py)。

Metadata 与插件扩展

模板还带有一个 JSON 格式的metadata字段,供各类插件使用,内部代码不直接使用。同时,渲染上下文会经过插件注册表处理:get_plugin_context()会调用所有注册了 Report 混合类的插件的add_report_context()方法(见 models.py),因此插件可以为报告注入自定义上下文变量。

报告安全:URL 抓取与 SSRF 防护

报告模板天生强大——它们可以访问完整的 Django 模板语言以及 InvenTree 数据库中的模型数据,因此模板上传仅限 staff 用户。同时,WeasyPrint 渲染 PDF 时可能发起外联请求加载 HTML 中引用的图片、样式表和字体,InvenTree 通过自定义 URL 抓取器InvenTreeURLFetcher(见 fetcher.py)加以限制:

URL 类型行为
data:URI始终允许——自包含,无网络访问
file://始终拦截——资源与图片必须以内联data:URI 形式在进入 WeasyPrint 前准备好
http/https默认禁用,可在全局设置中开启(见下方远程 URL 抓取
其他 scheme始终拦截

同时,HTTP 重定向被禁用allow_redirects=False,见 fetcher.py):通过校验的 URL 不能被重定向到内部地址。此外,抓取器还在 WeasyPrint 实际建立连接时通过ssrf_safe_context()守护 DNS 解析过程,防止 DNS rebinding 攻击绕过预校验。

远程 URL 抓取(REPORT_FETCH_URLS)

系统设置Report URL FetchingREPORT_FETCH_URLS)控制模板中http://https://URL 是否允许,默认禁用。即使启用,URL 在发起请求前仍会针对私有、回环、链路本地与保留 IP 范围进行校验,防止模板被用作对内网服务的 SSRF(Server-Side Request Forgery) 攻击向量(校验逻辑见 fetcher.py)。

谨慎启用:开启远程 URL 抓取意味着报告模板能够触发 InvenTree 服务器发起外联 HTTP 请求。仅在模板确实需要时才启用,并确保模板在上线前经过审查。

资源文件的嵌入式处理

通过管理界面上传的资源文件(Asset Files)会被直接嵌入到渲染后的 PDF 中(以 base64data:URI 形式,经由 Django 存储 API 读取),不会经过 WeasyPrint 的 URL 抓取器。这意味着:

  • 资源文件不受远程 URL 抓取开关影响,始终可用;
  • 同样适用于 S3 等远程存储后端。

源码中对应的 base64 编码辅助函数为encode_file_base64()encode_image_base64()(见 helpers.py),另有更多资源嵌入辅助函数可供模板调用。可复用的片段模板(Report Snippets)与资源文件均由管理员在 Admin Center 的Reporting分组下管理,详见片段模板文档。

延伸阅读

  • 模板总览与创建模板(含全局报告选项、Debug 模式)
  • 上下文变量全集(全局、报告、标签及各模型类型)
  • 模型上下文(底层字段与属性)
  • WeasyPrint 模板渲染与本地化注意事项
  • 内置报告模板源码 —— 官方提供了一套开箱即用的默认报告模板(采购/销售/退货/调拨订单、BOM、库存位置、测试报告等),虽然通常比较简单,但作为自定义报告的最佳起点

【免费下载链接】InvenTreeOpen Source Inventory Management System项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询