第22讲、Odoo18 QWeb 模板引擎详解_odoo如何使用自定义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-if
/ t-elif
/ t-else
完成
t-set
t-call
t-field
t-esc
t-raw
三、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 模板结构
- 使用
触发前端调试工具
- 报表调试可用
--log-level=debug
输出渲染上下文 t-field
可自动格式化输出复杂字段(如货币、日期)
六、实战案例:门户表单 + 控制器
1. 业务场景
实现门户页面 /project/apply
,展示项目申请表,用户提交后由控制器处理并保存至数据库。
2. 数据模型
# models/project_application.pyfrom 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 表单模板
<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.pyfrom odoo import httpfrom 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
,填写并提交表单,系统将保存数据并显示成功页面。
七、进阶建议
request.env.user
获取当前用户信息enctype=\"multipart/form-data\"
,后端用 request.httprequest.files
处理return request.redirect(\'/thank-you\')