# 模板引擎技术文档 ## 概述 本模块实现了一个基于 Jinja2 的自定义模板引擎系统,支持通过 URL 映射到文件路径的方式加载模板,并集成了异步渲染功能。该系统适用于 Web 服务中动态页面的生成和管理。 主要特性包括: - 自定义模板加载器(`TmplLoader`),支持多路径查找、继承机制与索引页自动识别。 - 支持配置化的编码格式读取模板文件。 - 异步渲染能力(`render_async`)。 - 与项目中的 `Url2File` 和 `ServerEnv` 组件无缝集成。 --- ## 模块依赖 ```python import os import codecs from appPublic.Singleton import SingletonDecorator from appPublic.jsonConfig import getConfig from jinja2 import Template, Environment, BaseLoader from .serverenv import ServerEnv from .url2file import Url2File, TmplUrl2File ``` > **说明**: > - `appPublic`: 项目公共库,提供单例模式和 JSON 配置读取功能。 > - `jinja2`: 核心模板引擎库。 > - `serverenv`: 服务器运行环境对象,用于全局共享资源。 > - `url2file`: 将 URL 路径转换为本地文件路径的工具类,`TmplUrl2File` 是其针对模板的扩展。 --- ## 核心类定义 ### `TmplLoader(BaseLoader, TmplUrl2File)` 自定义 Jinja2 模板加载器,结合了 `BaseLoader` 和 `TmplUrl2File` 的功能,支持从多个路径中按规则查找 `.tmpl` 类型的模板文件。 #### 构造函数 ```python def __init__(self, paths, indexes, subffixes=['.tmpl'], inherit=False) ``` | 参数 | 类型 | 描述 | |------|------|------| | `paths` | `list[str]` | 模板文件搜索路径列表,按顺序查找。 | | `indexes` | `list[str]` | 索引页名称(如 `index.tmpl`, `default.tmpl`),用于目录访问时自动匹配默认页。 | | `subffixes` | `list[str]` | 允许的模板文件后缀,默认为 `['.tmpl']`。可扩展支持其他后缀。 | | `inherit` | `bool` | 是否启用路径继承机制(由 `TmplUrl2File` 实现)。 | > ⚠️ 注意:需同时调用父类 `BaseLoader` 和 `TmplUrl2File` 的初始化方法。 #### 方法 ##### `get_source(env: Environment, template: str) -> tuple[str, str, callable]` 获取指定模板的源码内容。 **返回值**(符合 Jinja2 加载器规范): - `source`: 模板文本内容(字符串) - `filename`: 实际文件路径 - `uptodate`: 可调用对象,判断文件是否被修改(基于 mtime) **流程说明**: 1. 读取全局配置中的网站编码(`config.website.coding`)。 2. 使用 `url2file()` 将模板名映射为实际文件路径。 3. 若文件不存在,抛出 `TemplateNotFound` 错误。 4. 以指定编码读取文件内容。 5. 返回 `(source, filepath, is_unchanged_lambda)`。 ##### `join_path(name: str, parent: str) -> str` 实现模板中 `{% extends %}` 或 `{% include %}` 时相对路径的解析。 使用 `TmplUrl2File.relatedurl()` 计算相对于父模板的路径。 ##### `list_templates() -> list` 当前未实现模板枚举功能,固定返回空列表。 > 后续可扩展为扫描所有路径下的模板并去重返回。 --- ### `TemplateEngine(Environment)` 封装 Jinja2 `Environment` 的模板执行环境,提供更便捷的异步渲染接口。 #### 构造函数 ```python def __init__(self, loader=None) ``` | 参数 | 类型 | 描述 | |------|------|------| | `loader` | `TmplLoader` | 模板加载器实例,若不传则使用默认加载器。 | **额外属性**: - `urlpaths`: (预留字段)可用于缓存 URL 到模板的映射。 - `loader`: 保存引用以便内部调用。 #### 方法 ##### `join_path(template: str, parent: str) -> str` 代理至 `self.loader.join_path()`,确保路径解析一致性。 ##### `async render(___name: str, **globals) -> str` 异步渲染指定模板。 | 参数 | 类型 | 描述 | |------|------|------| | `___name` | `str` | 模板名称(URL 风格路径) | | `**globals` | `dict` | 渲染上下文变量 | **逻辑步骤**: 1. 调用 `get_template()` 获取模板对象。 2. 执行 `render_async()` 进行异步渲染。 3. 返回渲染后的 HTML 字符串。 > ✅ 支持异步过滤器、协程调用等高级特性。 --- ## 初始化函数 ### `setupTemplateEngine() -> None` 全局设置函数,用于初始化模板引擎并注入到服务器环境中。 #### 功能流程 1. 读取配置:`getConfig()` 获取全局配置对象。 2. 提取处理器配置中类型为 `'tmpl'` 的后缀列表: ```python subffixes = [i[0] for i in config.website.processors if i[1] == 'tmpl'] ``` 示例:若配置为 `[('.html', 'tmpl'), ('.tmpl', 'tmpl')]`,则支持 `.html` 和 `.tmpl` 文件作为模板。 3. 创建 `TmplLoader` 实例,启用继承模式。 4. 初始化 `TemplateEngine` 并绑定加载器。 5. 将引擎挂载到单例 `ServerEnv()` 的 `tmpl_engine` 属性上,供全局使用。 #### 示例配置片段(JSON/YAML) ```json { "website": { "coding": "utf-8", "paths": [ "/var/www/templates", "/opt/app/default_tmpl" ], "indexes": ["index.tmpl", "default.tmpl"], "processors": [ [".html", "tmpl"], [".tmpl", "tmpl"], [".js", "static"] ] } } ``` --- ## 使用示例 ```python # 初始化模板引擎(通常在应用启动时调用一次) setupTemplateEngine() # 获取引擎实例 g = ServerEnv() engine = g.tmpl_engine # 异步渲染模板 result = await engine.render('/user/profile.html', name='Alice', age=30) print(result) # 输出渲染后的 HTML 内容 ``` 在模板中也可以使用继承或包含: ```jinja2 {# base.tmpl #}
{% block content %}{% endblock %} ``` ```jinja2 {# profile.tmpl #} {% extends "base.tmpl" %} {% block content %}