构建 PDF 报告¶
重要
本教程是 服务器框架入门 教程的扩展。确保您已完成该教程,并使用您构建的 estate
模块作为本教程练习的基础。
我们之前在 第 14 章:QWeb简史 中了解了 QWeb,它被用于构建看板视图。现在我们将扩展 QWeb 的另一个主要用途:创建 PDF 报告。一个常见的业务需求是能够创建发送给客户或内部使用的文档。这些报告可以用来以有组织的模板形式汇总和显示信息,从而以不同的方式支持业务。Odoo 还可以轻松地将我们公司的页眉和页脚添加到报告中,而无需额外的工作。
与本主题相关的文档可以在 QWeb 模板、QWeb 报表 以及操作参考中的 报告动作 ( ir.actions.report ) 部分找到。
文件结构¶
PDF 报告的核心是其 QWeb 模板。通常还需要一个对应的 ir.actions.report
,以便将报告包含在模块的业务逻辑中。对于文件名或存放位置没有严格规定,但这两部分通常存储在模块目录顶层的 report
文件夹中的两个独立文件中。如果一个模块包含多个或较长的报告模板,则它们通常按逻辑分布在不同的文件中,文件名以其包含的报告命名。所有报告的操作通常都存储在同一个以 _reports.xml
结尾的文件中,无论它包含多少个报告。
因此,您的工作目录树预计会如下所示:
estate
├── models
│ ├── *.py
│ └── __init__.py
├── report
│ ├── estate_property_templates.xml
│ └── estate_property_reports.xml
├── security
│ └── ir.model.access.csv
├── views
│ └── *.xml
├── __init__.py
└── __manifest__.py
别忘了将模板和操作视图所涉及的文件添加到您的 __manifest__.py
中。在这种情况下,您需要将文件添加到 data
列表中,并记住清单中列出的文件是按顺序加载的!
基本报告¶
注解
目标:在本节结束时,我们将能够打印一份显示某房产所有报价的报告。

在我们的房地产示例中,我们可以创建许多有用的报告。其中一个简单的报告是可以显示某房产的所有报价。
报告数据¶
在做任何事情之前,我们首先需要一些数据来填充我们的报告,否则本教程将不会很有趣。在创建报告时,您需要一些数据来测试您的报告代码,并检查结果是否符合预期。建议使用覆盖大部分或全部预期用例的数据进行测试。对于我们的简单报告,一个好的数据集应包括:
至少 3 个房产,其中 1 个为“已售出”,1 个为“已收到报价”,1 个为“新房产”。
我们的“已售出”和“已收到报价”的房产至少应有 2-3 个报价。
如果您还没有这样的数据集,您可以选择以下方法之一:
完成 定义模块数据 教程(如果您尚未完成),并在演示数据中添加额外的案例(您可能需要创建一个新的数据库来加载演示数据)。
手动在数据库中创建数据。
将此 数据文件 复制到您的 estate 模块中的新目录(data)中,并将 这些行 复制到您的 __manifest__.py 文件中(您可能需要创建一个新的数据库以加载演示数据)。
在继续之前,请浏览数据库中的数据并确保数据符合预期。当然,您可以在编写报告代码之后再添加数据,但这样您将无法在编写代码时逐步测试代码的部分功能。对于复杂的报告来说,这可能会使错误检查和代码调试变得更加困难。
最小模板¶
一个最小可行模板可以在 报表模板 文档的“最小可行模板”部分查看。我们可以修改此示例来构建我们的最小房产报价模板文件:
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<template id="report_property_offers">
<t t-foreach="docs" t-as="property">
<t t-call="web.html_container">
<t t-call="web.external_layout">
<div class="page">
<h2>
<span t-field="property.name"/>
</h2>
<div>
<strong>Expected Price: </strong>
<span t-field="property.expected_price"/>
</div>
<table class="table">
<thead>
<tr>
<th>Price</th>
</tr>
</thead>
<tbody>
<t t-set="offers" t-value="property.mapped('offer_ids')"/>
<tr t-foreach="offers" t-as="offer">
<td>
<span t-field="offer.price"/>
</td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</t>
</template>
</odoo>
我们文件中的大多数 Odoo 特定内容(即非 HTML 部分)已在最小可行模板部分中解释。我们的模板中还有一些其他功能:
使用了
class="table"
属性,使我们的表格具有一些良好的格式。Twitter Bootstrap(在本例中我们使用了它的表格类)和 Font Awesome(用于添加图标)类可以在您的报告模板中使用。使用了
t-set
、t-value
、t-foreach
和t-as
,以便我们可以遍历所有的offer_ids
。
如果您已经熟悉网站模板引擎,那么 QWeb 指令(即 t-
命令)可能不需要太多解释,您可以直接查看其 文档 并跳过到下一小节。
否则,建议您进一步阅读相关内容(Wikipedia 提供了一个很好的高层描述),但总体思路是 QWeb 提供了基于 Odoo 数据和简单命令动态生成网页代码的能力。也就是说,QWeb 可以访问记录集数据(和方法),并处理简单的编程操作,例如设置和访问临时变量。例如,在上述示例中:
t-set
创建了一个名为“offers”的临时变量,其值由t-value
设置为当前estate.property
记录集的offer_ids
。t-foreach
和t-as
的用法等同于 Python 中的:
for offer in offers:
报告操作¶
现在我们有了一个模板,我们需要通过 ir.actions.report
在应用中使其可访问。ir.actions.report
的一个实际示例是 这里 ,对应于 此模板 。其内容都在 文档 中有详细说明。
ir.actions.report
主要通过模型视图的打印菜单使用。在实际示例中,binding_model_id
指定了报告应显示的模型视图,Odoo 会自动为您添加它。报告操作的另一个常见用例是将其链接到按钮,正如我们在 第 9 章:准备好迎接一些操作了吗? 中学到的那样。这对于仅在特定条件下有意义的报告非常有用。例如,如果我们想制作一份“最终销售”报告,我们可以将其链接到一个“打印销售信息”按钮,该按钮仅在属性状态为“已售出”时出现在表单视图中。

您可能已经注意到或疑惑为什么我们的报告模板会遍历一个记录集。当我们的模板传递多个记录时,它可以为所有记录生成一份 PDF 报告。在列表视图中选择多个记录并使用打印菜单将演示这一点。
创建报告¶
最后,您现在知道在哪里创建文件以及文件的内容应该如何组织。祝您愉快地制作报告!
Exercise
创建一份报告。
将最小模板小节中的房产报价报告添加到房产视图的打印菜单中。
通过添加更多数据来改进报告。请参考本节的 目标,了解可以添加哪些额外数据,并随意添加更多内容。
奖励任务:通过添加一些逻辑使报告更加灵活,当某个房产没有报价时,我们不创建表格,而是写一些关于目前尚无报价的内容。提示:您需要使用
t-if
和t-else
。
请务必检查您的 PDF 报告是否与预期数据匹配。
子模板¶
注解
目标:在本节结束时,我们将拥有一个在两个报告中使用的子模板。

使用子模板有两个主要原因。一个是当处理超长或复杂模板时,使代码更易于阅读。另一个是尽可能重用代码。我们简单的房产报价报告很有用,但列出房产报价信息对不止一个报告模板来说可能是有用的。一个例子是列出销售人员所有房产报价的报告。
通过阅读有关子模板的 文档 和/或查看 示例 ,看看您是否能理解如何调用子模板(请记住,无论是在报告还是 Odoo 视图中,QWeb 使用的控制流都是相同的)。
Exercise
创建并使用子模板。
将报价表部分拆分为一个独立的模板。请务必检查原始报告在拆分后是否仍能正确打印。
为
res.users
添加一份新报告,允许您打印在其表单视图中可见的所有房地产属性(例如,在“设置”应用中)。在同一份报告中包含每个销售人员的房产报价。提示:由于在这种情况下binding_model_id
不在房地产模块内,因此您需要使用ref="base.model_res_users"
。最终结果应类似于本节 目标 中的图片。
请务必检查您的报告是否与预期数据匹配!
报告继承¶
注解
目标:在本节结束时,我们将在 estate_account
模块中继承房产报告。

QWeb 中的继承使用与 视图继承 相同的 xpath
元素。不过,QWeb 模板引用其父模板的方式有所不同。只需向 template
元素添加 inherit_id
属性,并将其设置为 module.parent_template_id,即可轻松实现。
我们在 estate_account
中没有向任何房地产模型添加新字段,但我们仍然可以向现有的房产报告中添加信息。例如,我们知道任何“已售出”的房产都已经为其创建了发票,因此我们可以将此信息添加到报告中。
Exercise
继承一份报告。
扩展房产报告以包含有关发票的一些信息。您可以参考本节的 目标 获得灵感(例如,当房产状态为“已完成”时打印一行,否则不打印任何内容)。
再次提醒,请务必检查您的报告是否与预期数据匹配!
附加功能¶
所有以下附加功能在 QWeb 报表 文档中有进一步描述,包括如何实现每个功能。
翻译¶
我们都知道,Odoo 通过自动和手动翻译支持多种语言。QWeb 报告也不例外!请注意,如果模板的文本内容中存在不必要的空格,有时翻译可能无法正常工作,因此请尽量避免(尤其是前导空格)。
报表是网页¶
您可能已经听腻了 QWeb 创建 HTML 的说法,但我们再说一次!用 QWeb 编写报告的一个巧妙功能是它们可以在浏览器中查看。如果您想嵌入一个指向特定报告的超链接,这可能会很有用。请注意,常规的安全检查仍然适用,以防止未经授权的用户访问报告。
条形码¶
Odoo 内置了一个条形码图像生成器,允许将条形码嵌入到您的报告中。查看相应的 代码 ,了解所有支持的条形码类型。