You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何递归获取Django模板中所有{% extend/include %}加载的模板路径?

Django递归获取模板依赖的解决方案

我使用Django框架,有一个名为name.html的模板,内容如下:

{% extends "some.html" %}
{% for page in pages %}
  {% include page.html_template_path %}
{% endfor %}

该模板会引入存储在page.html_template_path中的模板路径,且每个模板内部还可能继承或引入其他模板。现在需要递归获取所有通过{% extend ... %}和{% include %}标签加载的模板路径,但存在以下限制:

  • 正则表达式不可行(模板路径可能存在于变量、上下文或{% for %}标签等场景中)
  • 替换内置{% extend %}和{% include %}标签为自定义标签的方案不适用于我的项目
  • 尝试过的django-template-analyzer工具无法正确处理嵌套{% for %}这类复杂场景

基于Django模板AST解析的实现思路

Django模板系统会将模板解析为抽象语法树(AST),我们可以通过遍历AST节点识别extend和include标签,再递归处理依赖模板,同时覆盖变量、循环等复杂场景:

1. 核心处理逻辑

  • 使用Django的Template类解析模板,获取其节点列表
  • 遍历节点,识别ExtendsNode(对应{% extend %})和IncludeNode(对应{% include %})
  • 对ExtendsNode:直接提取父模板路径,递归解析父模板
  • 对IncludeNode:区分静态路径和动态路径处理:
    • 静态路径:直接提取字符串路径,递归解析
    • 动态路径(如page.html_template_path这类变量):若能获取上下文数据,代入变量值得到实际路径;若无法获取上下文,可记录变量表达式,或根据项目模板存储规则枚举可能路径
  • 处理循环节点(如ForNode):遍历循环体内的节点,同样识别并处理include标签

2. 示例代码实现

from django.template import Engine, Template
from django.template.base import ExtendsNode, IncludeNode, ForNode

def get_template_dependencies(template_path, engine=None, visited=None):
    # 用visited集合避免循环依赖和重复处理
    if visited is None:
        visited = set()
    if template_path in visited:
        return visited
    visited.add(template_path)
    
    engine = engine or Engine.get_default()
    try:
        # 加载模板源文件
        template_source, origin = engine.find_template(template_path)
        template = Template(template_source)
    except Exception:
        # 处理模板不存在/加载失败的情况
        return visited
    
    # 遍历模板所有节点
    for node in template.nodelist:
        process_node(node, engine, visited)
    
    return visited

def process_node(node, engine, visited):
    # 处理extend标签
    if isinstance(node, ExtendsNode):
        parent_path = node.parent_name.var if hasattr(node.parent_name, 'var') else node.parent_name
        # 静态路径直接递归解析
        if isinstance(parent_path, str):
            get_template_dependencies(parent_path, engine, visited)
    
    # 处理include标签
    elif isinstance(node, IncludeNode):
        include_path = node.template_name.var if hasattr(node.template_name, 'var') else node.template_name
        if isinstance(include_path, str):
            get_template_dependencies(include_path, engine, visited)
        else:
            # 动态路径处理:若能获取上下文,可在此处传入上下文解析变量
            # 示例:resolved_path = include_path.resolve(your_context)
            # get_template_dependencies(resolved_path, engine, visited)
            pass
    
    # 处理for循环节点,遍历循环体内的子节点
    elif isinstance(node, ForNode):
        for child_node in node.nodelist_loop:
            process_node(child_node, engine, visited)
    
    # 处理包含子节点的其他类型节点
    elif hasattr(node, 'nodelist'):
        for child in node.nodelist:
            process_node(child, engine, visited)

3. 关键注意事项

  • 动态路径处理:如果模板路径是变量,必须依赖上下文数据才能解析实际路径;若无法获取上下文,可根据项目模板的命名规则、存储目录枚举可能路径,或仅记录变量表达式
  • 异常处理:需捕获模板加载失败的异常,避免整个流程中断
  • 循环依赖防护:通过visited集合记录已处理的模板,防止无限递归

内容的提问来源于stack exchange,提问作者user3905355

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 20:43:32