第22讲、Odoo18 QWeb 模板引擎详解

news2025/6/9 14:24:55

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 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, fields

class 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 request

class 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 更灵活


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2405463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【原理解析】为什么显示器Fliker dB值越大,闪烁程度越轻?

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

Bootstrap Table开源的企业级数据表格集成

Bootstrap Table 是什么 ‌Bootstrap Table 是一个基于 Bootstrap 框架的开源插件&#xff0c;专为快速构建功能丰富、响应式的数据表格而设计。‌ 它支持排序、分页、搜索、导出等核心功能&#xff0c;并兼容多种 CSS 框架&#xff08;如 Semantic UI、Material Design 等&am…

vue3表格使用Switch 开关

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

【11408学习记录】考研写作双核引擎:感谢信+建议信复合结构高分模板(附16年真题精讲)

感谢信建议信 英语写作2016年考研英语&#xff08;二&#xff09;真题小作文题目分析写作思路第一段第二段锦囊妙句9&#xff1a;锦囊妙句12&#xff1a;锦囊妙句13&#xff1a;锦囊妙句18&#xff1a; 第三段 妙句成文 每日一句词汇第一步&#xff1a;找谓语第二步&#xff1a…

一套个人知识储备库构建方案

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

行李箱检测数据集VOC+YOLO格式2083张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2083 标注数量(xml文件个数)&#xff1a;2083 标注数量(txt文件个数)&#xff1a;2083 …

实践提炼,EtherNet/IP转PROFINET网关实现乳企数字化工厂增效

乳企数字化工厂的核心技术应用 1. 智能质检&#xff1a;机器视觉协议网关的协同 液态奶包装线&#xff08;利乐罐装&#xff09;的漏码检测生产线&#xff0c;其高速产线&#xff08;20,000包/小时&#xff09;需实时识别微小缺陷&#xff0c;但视觉系统&#xff08;康耐视Ca…

从以物换物到DeFi:交易的演变与Arbitrum的DeFi生态

交易的本质&#xff1a;从以物换物到现代金融 交易是人类社会经济活动的核心&#xff0c;是通过交换资源&#xff08;如货物、服务或货币&#xff09;满足各方需求的行为。其本质是价值交换&#xff0c;旨在实现资源的优化配置。交易的历史可以追溯到人类文明的起源&#xff0…

分类场景数据集大全「包含数据标注+训练脚本」 (持续原地更新)

一、作者介绍&#xff1a;六年算法开发经验、AI 算法经理、阿里云专家博主。擅长&#xff1a;检测、分割、理解、大模型 等算法训练与推理部署任务。 二、数据集介绍&#xff1a; 质量高&#xff1a;高质量图片、高质量标注数据&#xff0c;吐血标注、整理&#xff0c;可以作为…

Web后端开发(SpringBootWeb、HTTP、Tomcat快速入门)

目录 SpringBootWeb入门 Spring 需求&#xff1a; 步骤&#xff1a; HTTP协议&#xff1a; 概述&#xff1a; 请求协议&#xff1a; 响应协议&#xff1a; 协议解析&#xff1a; Web服务器-Tomcat&#xff1a; 简介&#xff1a; 基本使用&#xff1a; SpringBootWeb…

android binder(四)binder驱动详解2

二、情景分析 1、ServiceManager 启动过程 2. 服务注册 服务注册过程(addService)核心功能&#xff1a;在服务所在进程创建binder_node&#xff0c;在servicemanager进程创建binder_ref。其中binder_ref的desc在同一个进程内是唯一的&#xff1a; 每个进程binder_proc所记录的…

4G无线网络转串口模块 DTU-1101

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

机器学习方法实现数独矩阵识别器

目录 导包 工具函数构建说明 1. 基础图像处理工具 2. 图像预处理模块 3. 数独轮廓检测与定位 4. 网格划分与单元格提取 5. 数字特征提取 6. 多网格处理流程 数据流分析 核心算法详解 核心机器视觉方法 1. 透视变换校正算法 2. 数字区域提取算法 3. 多网格检测算法…

【Vmwrae】快速安装windows虚拟机

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

多线程3(Thread)

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

附加模块--Qt Shader Tools功能及架构解析

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

网络编程(计算机网络基础)

思维导图 认识网络 1.网络发展史 ARPnetA(阿帕网)->internet(因特网)->移动互联网->物联网 2.局域网与广域网 局域网 概念&#xff1a;的缩写是LAN&#xff08;local area network&#xff09;&#xff0c;顾名思义&#xff0c;是个本地的网络&#xff0c;只能实现…

在React 中安装和配置 shadcn/ui

1. 创建 React 项目 pnpm create vitelatest .选择模板&#xff1a;React TypeScript安装依赖&#xff1a;pnpm install2. 添加 Tailwind CSS pnpm add -D tailwindcss postcss autoprefixer修改 src/index.css 内容&#xff1a; import "tailwindcss";3. 配置 T…

WINUI——WINUI开发中谨慎使用x:Bind

原因——为什么需要谨慎使用x:Bind&#xff1f; 在实际开发中发现&#xff0c;使用它会导致VM回收不及时&#xff0c;可能导致内存泄漏。 那为何要在项目中使用它呢&#xff1f; 因为&#xff1a;{x&#xff1a;Bind} 标记扩展&#xff08;Windows 10 的新增功能&#xff09;…

MSYS2 环境配置与 Python 项目依赖管理笔记

#工作记录 MSYS2 环境配置 安装和更新 MSYS2 初始安装 下载并安装 MSYS2&#xff1a; 访问 MSYS2 官方网站 并下载安装包。 按照安装向导完成安装。 更新 MSYS2&#xff1a; 打开 MSYS2 终端&#xff08;MSYS2 MINGW64&#xff09;。 更新包数据库和核心系统包&#xff1…