> 技术文档 > 第22讲、Odoo18 QWeb 模板引擎详解_odoo如何使用自定义qweb模板

第22讲、Odoo18 QWeb 模板引擎详解_odoo如何使用自定义qweb模板


Odoo QWeb 模板引擎详解与实战

Odoo 的 QWeb 是其自研的模板引擎,广泛应用于 HTML、XML、PDF 等内容的生成,支撑了前端页面渲染、报表输出、门户页面、邮件模板等多种场景。本文将系统介绍 QWeb 的核心用法、工作原理,并通过实战案例演示如何在门户页面实现表单提交与数据存储。


一、QWeb 简介

QWeb 是 Odoo 原生的 XML/HTML 模板引擎,采用 XML 语法,通过丰富的 t- 前缀指令(如 t-foreacht-ift-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,填写并提交表单,系统将保存数据并显示成功页面。


七、进阶建议

功能 实现方式 表单校验 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模板
第22讲、Odoo18 QWeb 模板引擎详解_odoo如何使用自定义qweb模板