如何实现Django模板标签同时输出原代码与渲染结果?
实现Django示例模板标签的方案
核心思路
要同时拿到标签内的原始未渲染文本和渲染后的结果,得绕开Django默认的模板解析逻辑——普通标签内容会被解析成StaticNode这类节点,没法直接获取原始字符串。我们需要在解析阶段就保存原始文本,同时保留解析后的节点用于生成渲染结果。
具体实现步骤
1. 自定义模板标签解析器
模仿verbatim标签的特殊解析逻辑,同时保留原始文本和可渲染节点:
from django import template from django.template.base import Parser register = template.Library() class ExampleNode(template.Node): def __init__(self, raw_text, rendered_nodes): self.raw_text = raw_text self.rendered_nodes = rendered_nodes def render(self, context): # 生成渲染后的内容 rendered_content = self.rendered_nodes.render(context) # 返回对比展示的HTML结构 return f""" <div class="demo-example"> <h4>原始模板代码</h4> <pre>{template.defaultfilters.escape(self.raw_text)}</pre> <h4>渲染结果</h4> <pre>{template.defaultfilters.escape(rendered_content)}</pre> </div> """ @register.tag(name='example') def do_example(parser, token): # 提取{% example %}到{% endexample %}之间的原始文本 raw_text = parser.get_until('endexample') # 重置解析位置,重新解析这段文本为可渲染节点 temp_parser = Parser(parser.source, parser.origin) # 定位到当前标签后的token区间 start_idx = parser.tokens.index(token) + 1 end_idx = start_idx + raw_text.count('\n') + 1 temp_parser.tokens = parser.tokens[start_idx:end_idx] rendered_nodes = temp_parser.parse(('endexample',)) # 跳过结束标签 temp_parser.next_token() return ExampleNode(raw_text.strip(), rendered_nodes)
2. 关键细节说明
- 获取原始文本:
parser.get_until('endexample')直接提取标签内的原始字符串,这是verbatim标签能保留纯文本的核心逻辑,避免内容被提前解析。 - 重新解析生成节点:把原始文本传入临时解析器,生成正常的可渲染节点列表,以此得到最终渲染结果。
- 转义处理:用
escape过滤器处理文本,避免HTML标签被浏览器解析,保证代码原样展示。
3. 模板使用示例
{% example %} import * as fancy from "{% static 'jslib/fancy.min.js' %}"; {% endexample %}
输出会同时展示原始的模板代码,以及渲染后的import * as fancy from "/static/jslib/fancy.min.js";。
简化替代方案
如果不想操作解析器,也可以手动重复内容:
<div class="demo-example"> <h4>原始模板代码</h4> <pre>{% verbatim %}import * as fancy from "{% static 'jslib/fancy.min.js' %}";{% endverbatim %}</pre> <h4>渲染结果</h4> <pre>{{ "import * as fancy from \"{% static 'jslib/fancy.min.js' %}\";"|safe }}</pre> </div>
但这种方式需要重复编写内容,不如自定义标签高效。
内容的提问来源于stack exchange,提问作者run_the_race
相关产品推荐
相关产品推荐

