第22讲、Odoo18 QWeb 模板引擎详解
Odoo QWeb 模板引擎详解与实战
Odoo 的 QWeb 是其自研的模板引擎,广泛应用于 HTML、XML、PDF 等内容的生成,支撑了前端页面渲染、报表输出、门户页面、邮件模板等多种场景。本文将系统介绍 QWeb 的核心用法、工作原理,并通过实战案例演示如何在门户页面实现表单提交与数据存储。
一、QWeb 简介
QWeb 是 Odoo 原生的 XML/HTML 模板引擎,采用 XML 语法,通过丰富的 t- 前缀指令(如 t-foreach
、t-if
、t-call
等)实现模板逻辑控制。与 Jinja2 相比,QWeb 更加结构化、安全,适合可视化编辑器和网页构建器场景。
QWeb 支持两大类渲染方式:
- 前端渲染:用于 Web 页面(如门户、报表、邮件预览等)
- 后端渲染:用于生成 PDF 报表、邮件内容等(通过 Python 代码调用)
二、QWeb 核心指令(t-指令)
指令 | 用法 | 示例 |
---|---|---|
t-foreach | 遍历 | <t t-foreach="docs" t-as="doc">...</t> |
t-if / t-elif / t-else | 条件判断 | <t t-if="doc.state == 'done'">完成</t> |
t-set | 设置变量 | <t t-set="total" t-value="sum(docs.mapped('amount'))"/> |
t-call | 引用模板 | <t t-call="module_name.template_name"/> |
t-field | 渲染字段 | <span t-field="doc.partner_id"/> |
t-esc | 转义输出 | <span t-esc="doc.name"/> |
t-raw | 原样输出(不转义) | <div t-raw="doc.html_description"/> |
三、QWeb 应用场景
1. Web 前端视图(门户、自定义页面等)
QWeb 模板常用于 ir.ui.view
(type=‘qweb’)视图,广泛应用于门户表单、公共页面等。例如:
<template id="my_portal_form" name="My Portal Form"><form action="/my/form/submit" method="post"><input type="text" name="name"/><t t-if="user_id"><input type="hidden" name="user_id" t-att-value="user_id"/></t></form>
</template>
通过控制器渲染模板:
return request.render('my_module.my_portal_form', {'user_id': user.id})
2. 报表生成(PDF 报表)
Odoo 利用 QWeb 生成 PDF 报表(如发票、订单等),通过 report_qweb
模块实现。
模板定义:
<template id="report_order_document"><t t-call="web.external_layout"><t t-set="doc" t-value="docs[0]"/><div class="page"><h2>订单号:<span t-field="doc.name"/></h2></div></t>
</template>
渲染调用:
return self.env.ref('sale.report_saleorder').report_action(self)
3. 控制器网页(如公开网站或门户)
结合 Web Controller 使用:
@http.route('/public/page', type='http', auth='public', website=True)
def public_page(self, **kwargs):return request.render('my_module.public_template', {'data': some_data})
四、QWeb 工作原理
1. 模板加载
QWeb 模板存储于 ir.ui.view
表(type=‘qweb’),Odoo 启动时会将其缓存至内存,供后续渲染调用。
2. 渲染引擎
QWeb 的核心为 QWebEngine
(Python 实现):
- 解析模板为 DOM 树结构
- 根据上下文渲染 t-指令
- 输出最终 HTML 字符串
常见调用方式:
- Web 控制器:
request.render(template_name, context)
- 后端报表:
self.env.ref('module.report_template_id').render(context)
3. 继承机制(t-inherit)
QWeb 支持模板继承,类似 XML 视图继承:
<template id="my_template_inherit" inherit_id="base.template_to_inherit"><xpath expr="//div[@id='target']" position="replace"><div>新的内容</div></xpath>
</template>
五、开发与调试建议
- 开启开发者模式,便于查看 QWeb 模板结构
- 使用
<t t-debug="1">
触发前端调试工具 - 报表调试可用
--log-level=debug
输出渲染上下文 t-field
可自动格式化输出复杂字段(如货币、日期)
六、实战案例:门户表单 + 控制器
1. 业务场景
实现门户页面 /project/apply
,展示项目申请表,用户提交后由控制器处理并保存至数据库。
2. 数据模型
# models/project_application.py
from odoo import models, fieldsclass ProjectApplication(models.Model):_name = 'project.application'_description = 'Project Application'name = fields.Char(string='Applicant Name', required=True)email = fields.Char(string='Email')project_name = fields.Char(string='Project Name')description = fields.Text(string='Project Description')
3. QWeb 表单模板
<!-- views/project_application_templates.xml -->
<odoo><template id="project_application_form" name="Project Application Form"><t t-call="website.layout"><div class="container mt-5"><h2>项目申请表</h2><form action="/project/apply/submit" method="post" class="form-group"><input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/><div class="form-group"><label>姓名</label><input type="text" name="name" class="form-control" required/></div><div class="form-group"><label>Email</label><input type="email" name="email" class="form-control"/></div><div class="form-group"><label>项目名称</label><input type="text" name="project_name" class="form-control"/></div><div class="form-group"><label>项目描述</label><textarea name="description" class="form-control"></textarea></div><button type="submit" class="btn btn-primary mt-2">提交申请</button></form></div></t></template><template id="project_application_success" name="Application Success"><t t-call="website.layout"><div class="container mt-5"><h2>提交成功!</h2><p>感谢您的申请,我们会尽快处理。</p></div></t></template>
</odoo>
4. 控制器逻辑
# controllers/main.py
from odoo import http
from odoo.http import requestclass ProjectApplicationController(http.Controller):@http.route('/project/apply', type='http', auth='public', website=True)def apply_form(self, **kwargs):return request.render('your_module_name.project_application_form')@http.route('/project/apply/submit', type='http', auth='public', website=True, csrf=True)def apply_form_submit(self, **post):request.env['project.application'].sudo().create({'name': post.get('name'),'email': post.get('email'),'project_name': post.get('project_name'),'description': post.get('description'),})return request.render('your_module_name.project_application_success')
5. Manifest 配置
# __manifest__.py
'data': ['views/project_application_templates.xml',
],
6. 访问测试
启动 Odoo 后,访问 http://localhost:8069/project/apply
,填写并提交表单,系统将保存数据并显示成功页面。
七、进阶建议
功能 | 实现方式 |
---|---|
表单校验 | HTML5 校验 + 控制器后端校验 |
自动填充用户信息 | 控制器中通过 request.env.user 获取当前用户信息 |
文件上传 | 表单添加 enctype="multipart/form-data" ,后端用 request.httprequest.files 处理 |
提交后跳转页面 | 使用 return request.redirect('/thank-you') |
八、总结
项目 | 描述 |
---|---|
渲染引擎 | QWebEngine(Python 层) |
应用场景 | Web 页面、报表模板、控制器页面、门户表单 |
优点 | 安全、结构化、可嵌套、支持继承 |
与 Jinja2 比较 | 更偏向 XML 结构控制,适合 B2B 页面、门户、报表;Jinja 更灵活 |
相关文章:

第22讲、Odoo18 QWeb 模板引擎详解
Odoo QWeb 模板引擎详解与实战 Odoo 的 QWeb 是其自研的模板引擎,广泛应用于 HTML、XML、PDF 等内容的生成,支撑了前端页面渲染、报表输出、门户页面、邮件模板等多种场景。本文将系统介绍 QWeb 的核心用法、工作原理,并通过实战案例演示如何…...
OpenJudge | 大整数乘法
总时间限制: 1000ms 内存限制: 65536kB 描述 求两个不超过200位的非负整数的积。 输入 有两行,每行是一个不超过200位的非负整数,没有多余的前导0。 输出 一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果是342&am…...

【原理解析】为什么显示器Fliker dB值越大,闪烁程度越轻?
显示器Fliker 1 显示器闪烁现象说明2 Fliker量测方法2.1 FMA法2.2 JEITA法问题答疑:为什么显示器Fliker dB值越大,闪烁程度越轻? 3 参考文献 1 显示器闪烁现象说明 当一个光源闪烁超过每秒10次以上就可在人眼中产生视觉残留,此时…...

Bootstrap Table开源的企业级数据表格集成
Bootstrap Table 是什么 Bootstrap Table 是一个基于 Bootstrap 框架的开源插件,专为快速构建功能丰富、响应式的数据表格而设计。 它支持排序、分页、搜索、导出等核心功能,并兼容多种 CSS 框架(如 Semantic UI、Material Design 等&am…...
JDK8新特性之Steam流
这里写目录标题 一、Stream流概述1.1、传统写法1.2、Stream写法1.3、Stream流操作分类 二、Stream流获取方式2.1、根据Collection获取2.2、通过Stream的of方法 三、Stream常用方法介绍3.1、forEach3.2、count3.3、filter3.4、limit3.5、skip3.6、map3.7、sorted3.8、distinct3.…...

vue3表格使用Switch 开关
本示例基于vue3 element-plus 注:表格数据返回状态值为0、1。开关使用 v-model"scope.row.state 0" 会报错 故需要对写法做些修改,效果图如下 <el-table-column prop"state" label"入学状态" width"180" …...

【11408学习记录】考研写作双核引擎:感谢信+建议信复合结构高分模板(附16年真题精讲)
感谢信建议信 英语写作2016年考研英语(二)真题小作文题目分析写作思路第一段第二段锦囊妙句9:锦囊妙句12:锦囊妙句13:锦囊妙句18: 第三段 妙句成文 每日一句词汇第一步:找谓语第二步:…...

一套个人知识储备库构建方案
写文章的初心是做知识沉淀。 好记性不如烂笔头,将阶段性的经验总结成文章,下次遇到相同的问题时,查起来比再次去搜集资料快得多。 然而,当文章越来越多时,有一个问题逐渐开始变得“严峻”起来。 比如,我…...

行李箱检测数据集VOC+YOLO格式2083张1类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):2083 标注数量(xml文件个数):2083 标注数量(txt文件个数):2083 …...
QT进阶之路:带命名空间的自定义控件在Qt设计器与qss中的使用技巧
文章目录 0.前言1.带命名空间Qt自定义类在QT设计器中的使用技巧1.1 定义一个带命令空间QLabel自定义类1.2 在QT设计器中引入自定义控件类 2.带命名空间Qt自定义类在qss中的使用技巧2.1 命名空间在 QSS 中的特殊语法2.1 在QSS中定义带命名空间的样式 3.在项目中使用带命名空间的…...
矩阵详解:从基础概念到实际应用
矩阵详解:从基础概念到实际应用 目录 矩阵的基本概念矩阵的类型矩阵运算特殊矩阵矩阵的逆与伴随矩阵的秩与等价分块矩阵矩阵的应用 矩阵知识体系思维导图 mindmaproot((矩阵))基本概念定义mn数表元素aij矩阵记号基本术语行数和列数方阵与非方阵矩阵相等矩阵类型…...
Prompt工程学习之自我一致性
自我一致性 (Self-consistency) 概念:该技术通过对同一问题采样不同的推理路径,并通过多数投票选择最一致的答案,来解决大语言模型(LLM)输出的可变性问题。通过使用不同的温度(temp…...

实践提炼,EtherNet/IP转PROFINET网关实现乳企数字化工厂增效
乳企数字化工厂的核心技术应用 1. 智能质检:机器视觉协议网关的协同 液态奶包装线(利乐罐装)的漏码检测生产线,其高速产线(20,000包/小时)需实时识别微小缺陷,但视觉系统(康耐视Ca…...

从以物换物到DeFi:交易的演变与Arbitrum的DeFi生态
交易的本质:从以物换物到现代金融 交易是人类社会经济活动的核心,是通过交换资源(如货物、服务或货币)满足各方需求的行为。其本质是价值交换,旨在实现资源的优化配置。交易的历史可以追溯到人类文明的起源࿰…...
一文掌握 Tombola 抽象基类的自动化子类测试策略
深入解析 Python 抽象基类的自动化测试框架设计 在 Python 开发中,抽象基类(ABC)是定义接口规范的强大工具。本文将以 Tombola 抽象基类为例,详细解析其子类的自动化测试框架设计,展示如何通过 Python 的内省机制实现…...
vue.js not detected解决方法
如果你在开发环境中遇到“Vue.js not detected”的错误,这通常意味着你的项目没有正确设置或者配置以识别Vue.js。下面是一些解决这个问题的步骤: 1. 确认Vue.js已正确安装 首先,确保你的项目中已经正确安装了Vue.js。你可以通过以下命令来…...
Redis 知识点一
参考 Redis - 常见缓存问题 - 知乎 Redis的缓存更新策略 - Sherlock先生 - 博客园 三种缓存策略:Cache Aside 策略、Read/Write Through 策略、Write Back 策略-CSDN博客 1.缓存问题 1.1.缓存穿透 大量请求未命中缓存,直接访问数据库。 解决办法&…...

分类场景数据集大全「包含数据标注+训练脚本」 (持续原地更新)
一、作者介绍:六年算法开发经验、AI 算法经理、阿里云专家博主。擅长:检测、分割、理解、大模型 等算法训练与推理部署任务。 二、数据集介绍: 质量高:高质量图片、高质量标注数据,吐血标注、整理,可以作为…...
数据结构与算法——二叉树高频题目(1)
前言: 简单记录一下自己学习算法的历程,主要根据左老师自己的视频课进行,由于大部分课程涉及题目较多,所以分文章进行记录。 本文将简单记录一下二叉树的层序遍历和 Z 形层次遍历。 参考视频: 算法讲解036【必备】…...

Web后端开发(SpringBootWeb、HTTP、Tomcat快速入门)
目录 SpringBootWeb入门 Spring 需求: 步骤: HTTP协议: 概述: 请求协议: 响应协议: 协议解析: Web服务器-Tomcat: 简介: 基本使用: SpringBootWeb…...
CppCon 2015 学习:Memory and C++ debugging at Electronic Arts
这是关于 C 游戏开发中内存接口与调试工具演进 的介绍,主要回顾了从早期到现在平台上的内存与调试策略变化: 游戏平台演进与内存接口编程风格 2000年 (PlayStation 2) 编程风格偏向嵌入式 C 风格。系统资源有限(例如 32MB RAM)…...

android binder(四)binder驱动详解2
二、情景分析 1、ServiceManager 启动过程 2. 服务注册 服务注册过程(addService)核心功能:在服务所在进程创建binder_node,在servicemanager进程创建binder_ref。其中binder_ref的desc在同一个进程内是唯一的: 每个进程binder_proc所记录的…...

4G无线网络转串口模块 DTU-1101
4G无线网络转串口模块概述 4G无线网络转串口模块是一种工业通信设备,通过4G网络将串口(如RS232/RS485)设备接入互联网,实现远程数据传输与控制。适用于物联网(IoT)、工业自动化、远程监控等场景。 核心功能…...

机器学习方法实现数独矩阵识别器
目录 导包 工具函数构建说明 1. 基础图像处理工具 2. 图像预处理模块 3. 数独轮廓检测与定位 4. 网格划分与单元格提取 5. 数字特征提取 6. 多网格处理流程 数据流分析 核心算法详解 核心机器视觉方法 1. 透视变换校正算法 2. 数字区域提取算法 3. 多网格检测算法…...
OpenEuler服务器警告邮件自动化发送:原理、配置与安全实践
OpenEuler服务器警告邮件自动化发送:原理、配置与安全实践 在服务器的运维管理过程中,及时感知系统异常状态至关重要。当OpenEuler系统运行时,将服务器的警告信息实时推送至邮箱,能帮助运维人员快速响应潜在问题,保障…...
随机访问介质访问控制:网络中的“自由竞争”艺术
想象一场自由辩论赛——任何人随时可以发言,但可能多人同时开口导致混乱。这正是计算机网络中随机访问协议的核心挑战:如何让多个设备在共享信道中高效竞争?本文将深入解析五大随机访问技术及其智慧。 一、核心思想:自由竞争 冲突…...
【Redis】笔记|第9节|Redis Stack扩展功能
Redis Stack 扩展功能笔记(基于 Redis 7) 一、Redis Stack 概述 定位:Redis OSS 扩展模块(JSON、搜索、布隆过滤器等),提供高级数据处理能力。核心模块: RedisJSON:原生 JSON 支持…...

【Vmwrae】快速安装windows虚拟机
前言 虚拟机是我们在使用电脑进行开发或者平常工作时经常使用到的工具 它可以自定义各种硬件,运行各种不同的系统,且无论发生什么都不会影响到实体机。 教程主要讲了如何在零基础的情况下快速安装一台虚拟机。 下载安装 VMware Workstation Pro17 …...

多线程3(Thread)
wait / notify 线程调度是随机的,但是我们可以使用wait/notify进行规划。 join是控制线程结束顺序,而wait/notify是控制详细的代码块,例如: 线程1执行完一段代码,让线程2继续执行,此时线程2就通过wait进…...

附加模块--Qt Shader Tools功能及架构解析
Qt 6.0 引入了全新的 Shader Tools 模块,为着色器管理提供了现代化、跨平台的解决方案。 一、主要功能 核心功能 跨平台着色器编译 支持 GLSL、HLSL 和 MetalSL 着色器语言 可在运行时或构建时进行着色器编译 自动处理不同图形API的着色器变体 SPIR-V 支持 能…...