完全指南:模板可用的数据字典、作用域与合并报表用法)
InvenTree 报表上下文变量Report Context Variables完全指南模板可用的数据字典、作用域与合并报表用法【免费下载链接】InvenTreeOpen Source Inventory Management System项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree导读InvenTree 开源库存管理系统的**报表Report与标签Label**均基于 Django 模板渲染而模板所能访问的一切数据都来自上下文变量Context Variables。本文以 docs/docs/report/context_variables.md 为骨架结合report应用源码与模型实现系统讲解上下文变量的三层作用域全局 / 报表 / 标签、全部可渲染的模型类型及对应变量、merge合并报表的实战写法以及插件如何向上下文中注入自定义数据帮助你编写出可复用、可排查的 InvenTree 报表与标签模板。一、上下文变量是什么模板渲染的数据来源在 InvenTree 中Report 与 Label 本质上都是模型模板Model Template模板以 HTML 文件的形式上传针对某一类模型实例如Part、SalesOrder、StockItem渲染。渲染时框架会把一整套上下文变量context variables注入模板模板中通过 Django 模板语法如{{ variable }}、{% for %}来访问它们。从源码看渲染的入口在 src/backend/InvenTree/report/models.pyReportTemplateBase.render_as_string()将模板渲染为 HTML 字符串models.py#L252-L267ReportTemplateBase.get_context()负责拼接基础上下文与模型实例上下文context {**base_context, **instance.report_context()}models.py#L346-L359。这里有两个关键设计模型实例通过report_context()方法提供自己的上下文数据。该方法定义在report.mixins.InvenTreeReportMixin中src/backend/InvenTree/report/mixins.py#L57-L93返回一个TypedDict并带完整的类型注解——这个注解被后续的文档导出工具用来自动生成上下文变量文档表。上下文是分层的全局上下文对所有模板可见Report 模板额外叠加报表上下文Label 模板额外叠加标签上下文模型实例再叠加各自的模型上下文。后注入的键会覆盖前者的同名键。二、三层作用域Global / Report / Label2.1 全局上下文Global Context所有模板无论报表还是标签都可以访问以下全局变量变量类型说明base_urlstr当前 InvenTree 实例的基础 URLget_base_url()datedatetime.date当前日期datetimedatetime当前日期时间templateReportTemplateBase当前正在渲染的模板实例本身template_descriptionstr模板描述template_namestr模板名称template_revisionint模板修订号每次保存自动递增userAbstractUser \| None触发本次渲染的用户若可用这些变量由ReportTemplateBase.base_context()统一构造models.py#L333-L344。它们对 Report 与 Label 模板一视同仁是编写模板自身信息展示类功能的基础例如在页脚打印template_name与template_revision即可追溯模板版本。值得注意的是template_revision背后的机制ReportTemplateBase在save()时默认执行self.revision 1models.py#L211-L217因此模板每次编辑保存后修订号都会自增方便在生成的报表上标识版本。2.2 报表上下文Report Context所有Report 模板在全局上下文之外还可访问以下变量变量类型说明page_sizestr报表页面尺寸如A4横屏时为A4 landscapelandscapebool是否为横向布局mergebool是否为合并报表对多个选中项生成单份报表这三项由ReportTemplate.get_report_context()提供models.py#L423-L431其数据类型在ReportContextExtensionTypedDict中定义models.py#L181-L192。page_size的取值来自模板自身的page_size字段若未设置则回退到全局设置REPORT_DEFAULT_PAGE_SIZE默认A4横屏时在尺寸后追加landscape见get_report_size()models.py#L407-L421。merge直接映射模板的merge布尔字段models.py#L401-L405是判断当前是否处于合并渲染模式的最直接依据。2.3 标签上下文Label Context所有Label 模板在全局上下文之外还可访问以下变量变量类型说明widthfloat标签宽度mmheightfloat标签高度mmpage_stylestr \| None标签模板的 CSSpage样式应插入样式块顶部由LabelTemplate.get_context()提供models.py#L752-L783类型定义见LabelContextExtensionmodels.py#L167-L178。width/height对应标签模板上的两个尺寸字段最小值为 2mmMinValueValidator(2)page_style由generate_page_style()动态生成形如page { size: {width}mm {height}mm; margin: 0mm; }的 CSS 片段models.py#L736-L750标签模板可直接将其输出到style块内以精确控制打印尺寸。三、可渲染的模型类型Template Types报表与标签模板都必须绑定一个目标模型类型model_type字段框架只允许对以下模型进行渲染。该约束由report.validators.validate_report_model_type校验模型选项由report.helpers.report_model_options动态生成。模型类型描述companyCompany供应商 / 客户实例buildBuild Order制造工单实例buildlineBuild Order Line Item制造工单行项实例salesorderSales Order销售订单实例salesordershipmentSales Order Shipment销售订单发货批次实例returnorderReturn Order退货订单实例purchaseorderPurchase Order采购订单实例transferorderTransfer Order调拨订单实例stockitemStockItem库存项实例stocklocationStockLocation库存位置实例partPart物料实例每种模型类型除了拥有第一节所述的三层通用上下文外还会注入各自的模型上下文变量。下面以part为代表性示例展开其余模型可依同一思路使用。3.1 Part 的模型上下文Part 模板可访问的模型级变量由Part.report_context()定义src/backend/InvenTree/part/models.py#L557-L572类型注解在PartReportContext中part/models.py#L432-L461变量类型说明partPartPart 实例本身namestr物料名称descriptionstr物料描述IPNstr \| None内部料号revisionstr \| None物料版本categoryPartCategory \| None物料所属类别parametersdict[str, str]参数键值对parameters_map()bom_itemsQuerySet[BomItem]与该 Part 关联的全部 BOM 行test_templatesdict[str, PartTestTemplate]测试模板字典test_template_listQuerySet[PartTestTemplate]测试模板列表qr_datastr用于二维码的格式化数据qr_urlstr可嵌入二维码的 URL可以看到模板里常见的{{ part.name }}、{{ part.description }}、{{ part.category }}等写法背后就是这份 TypedDict 与report_context()的返回值。3.2 其余模型类型一览其余模型类型的上下文变量结构与part完全一致均由各自的report_context()方法提供且同样遵循核心对象以模型名命名 常用字段扁平暴露 关联对象挂载的模式。以几个典型为例company暴露company实例、名称、地址等字段stockitem暴露itemStockItem 实例、part关联的 Part、stock位置、supplier_part供应商料号等stocklocation暴露location实例及其层级信息purchaseorder / salesorder / returnorder / transferorder分别暴露order实例、行项集合、关联的供应商 / 客户、发货信息等build / buildline暴露build工单与buildline行项、关联的 Part、目标数量与实际数量等。提示每个模型类型的具体变量表在渲染后的官方文档页面中由{{ report_context(models, model_type) }}宏自动生成本文表格仅为说明机制具体字段以当前仓库版本的导出数据为准。3.3 模型字段与属性Model Context除了显式注入的上下文变量模板还可以直接访问底层模型实例的全部数据库字段以及通过report_attribute装饰器显式标记的property属性。相关说明见 docs/docs/report/model_context.mdFields模型上定义的数据库字段含从 mixin / 抽象基类继承的字段Properties被report_attribute显式标记、从而可在文档中发现的属性Related Models本身不可直接渲染、但被可渲染模型的字段或属性引用的关联模型如PartCategory、SupplierPart会被自动发现并收录。report_attribute装饰器定义在 src/backend/InvenTree/report/mixins.py#L13-L41其典型用法是标记在property的下一行property report_attribute(descriptionFormat a minimal barcode string) def barcode(self) - str: ...这也解释了为什么模板中可以放心使用诸如{{ part.category.name }}这类链式访问——上下文中的category本身就是PartCategory实例。四、合并报表merge一份 PDF 渲染多个对象当模板的merge字段设为True时InvenTree 会针对选中的多个对象只生成一份报表。此时通用上下文与报表上下文照常可用所有选中项的上下文被收集到instances列表中既可以用{% for instance in instances %}循环遍历也可以通过下标访问单个元素例如instance.0.name。merge模式的实现位于ReportTemplate.print()models.py#L547-L598框架会先为每个实例单独调用instance.report_context()并叠加插件上下文汇总到contexts[instances]后一次性渲染。而非合并模式下每个实例单独渲染一份 PDF最终由PdfWriter拼接成多页 PDFmodels.py#L665-L694。官方文档给出了一份完整的合并报表示例模板——为选中的多个 Part 生成一张表格每个 Part 占一行{% raw %} h2Merged Report for Selected Parts/h2 table tr thName/th thDescription/th /tr {% for part in instances %} tr td{{ part.name }}/td td{{ part.description }}/td /tr {% endfor %} /table {% endraw %}使用要点instances中的每个元素就是对应对象的模型上下文即report_context()的返回值因此part.name、part.description这类键可直接访问若只关心第 N 个元素可用下标形式instances.0.xxx合并模式下建议模板只渲染一份容器型HTML表格、清单页数控制交给page_size/landscape由于合并渲染只生成一份 PDF 附件attach_to_model打印时将报表作为附件挂到模型在该模式下同样适用。五、插件注入扩展上下文变量的官方通道官方文档明确指出custom plugins may also add additional context variables to the report context。这是 InvenTree 报表体系的可扩展性所在其底层实现如下Report 模板渲染前会调用get_plugin_context()遍历插件注册表中所有实现了report mixin的插件逐一调用plugin.add_report_context(template, instance, user, context)将返回值合并进最终上下文models.py#L448-L464Label 模板同理调用plugin.add_label_context(template, instance, user, context)models.py#L773-L781插件输出完成后还有report_callback()回调可对生成的报表做后处理models.py#L475-L489。也就是说如果默认上下文不满足需求例如需要注入来自第三方系统的数据、按权限过滤后的自定义字段正确的做法是编写一个报表插件通过add_report_context/add_label_context钩子把自定义变量挂到上下文中而不是去修改核心模型代码。插件的这一能力在官方插件文档 docs/docs/plugins/mixins/report.md 中有更完整的说明。六、上下文表从何而来自动化文档生成机制context_variables.md中那些{{ report_context(base, global) }}之类的占位宏在文档构建时会展开为真实的变量表格。这一机制的实现值得模板作者了解因为它保证了文档与源码永远同步Django 管理命令export_report_contextsrc/backend/InvenTree/InvenTree/management/commands/export_report_context.py通过类型注解反射扫描所有实现了InvenTreeReportMixin的模型把report_context()的返回类型TypedDict及其文档字符串解析为结构化 JSON输出到docs/generated/inventree_report_context.json文档构建脚本 docs/main.py 在启动时加载该 JSON并注册report_context()宏main.py#L498-L509宏按type_models/base与模型名查表渲染为| Variable | Type | Description |三列表格整个报告上下文体系含所有可渲染模型、相关模型则由reportable_model_context()与related_model_context()两个宏自动生成main.py#L532-L578无需手工维护模型清单。对模板作者而言这意味着在模板中引用的变量其官方权威清单就是源码中对应模型的report_context()返回值及其 TypedDict 注解。若某变量既不在全局 / 报表 / 标签上下文中也不在模型上下文中那它要么来自插件注入要么就是未被文档化的模型字段仍可直接访问但不受文档保证。七、实战建议与排查清单结合前三节的分层上下文与第四节源码逻辑编写 InvenTree 报表 / 标签模板时建议遵循以下要点先确定作用域模板里能用的变量 全局上下文 Report 上下文 或 Label 上下文 目标模型的模型上下文 插件注入。利用merge区分渲染模式{{ merge }}为True时使用instances列表否则用模型实例直接访问字段也可在模板中用{% if merge %}输出不同版式。引用字段前核对类型模型上下文里的变量要么是标量str/bool/ 数字要么是模型实例 / QuerySet / dict。对后三者分别用属性访问、{% for %}循环、key取值例如{{ part.category.name }}、{% for item in part.bom_items %}、{{ part.parameters.color }}。善用template_revision溯源在页脚输出{{ template_name }} (rev {{ template_revision }})便于核对生成文件对应的模板版本。需要自定义数据就写插件优先通过add_report_context/add_label_context扩展而不是依赖未文档化字段。排查模板变量缺失模板渲染失败或变量为空时优先回到三张表核对——全局表、报表 / 标签表、目标模型的report_context()返回字段若均无检查是否被插件覆盖或拼写是否与 TypedDict 键名一致。参考与延伸阅读本文主体文档docs/docs/report/context_variables.md模型字段与属性详解docs/docs/report/model_context.mdReport 模板开发指南docs/docs/report/report.mdLabel 模板开发指南docs/docs/report/labels.md渲染核心实现src/backend/InvenTree/report/models.py上下文 mixin 与report_attributesrc/backend/InvenTree/report/mixins.py上下文导出命令src/backend/InvenTree/InvenTree/management/commands/export_report_context.py文档宏实现docs/main.py插件扩展报表上下文docs/docs/plugins/mixins/report.md【免费下载链接】InvenTreeOpen Source Inventory Management System项目地址: https://gitcode.com/GitHub_Trending/in/InvenTree创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考