查询模板以获取所需的变量?

Vic*_*ler 12 django variables django-templates

我希望能够从文件中实例化一个模板(大概使用django.template.loader.get_template(filename)),然后确定应该在传递的任何上下文中定义的变量集.

我以为在Template对象上会有一个方法,但似乎没有.

我阅读了文档,我发现的最接近的是:

http://docs.djangoproject.com/en/1.0/topics/templates/#using-the-built-in-reference

建议进入管理界面以查看与给定视图关联的所有变量.

我不想通过管理界面,因为我想以编程方式执行此操作 - 我正在尝试编写测试.

我正在使用Django版本(1,0,2,'final',0)

更新:

我尝试了synack的答案并发现(通过filter_expression.var替换filter_expression.token,获取没有标签的变量的实际名称等等),它返回了在模板中本地定义的变量,但是没有工作对于在其扩展的父级中定义的变量.

例如,假设我有两个文件中的模板:

toyparent.html:

{%block base_results%}
Django is {{adjective}}
{%endblock base_results%}
Run Code Online (Sandbox Code Playgroud)

toychild.html:

{% extends "toyparent.html" %}

{%block base_results%}
    {{block.super}}
    I {{verb}} it.
{%endblock base_results %}
Run Code Online (Sandbox Code Playgroud)

我加载子模板:

>>> toy=django.template.loader.get_template('toychild.html')
Run Code Online (Sandbox Code Playgroud)

这正确呈现:

>>> toy.render(django.template.Context(dict(adjective='cool',verb='heart')))
u'\n    \nDjango is cool\n\n    I heart it.\n\n'
Run Code Online (Sandbox Code Playgroud)

但我无法从中得到两个变量:

>>> v=toy.nodelist.get_nodes_by_type(VariableNode)
>>> for k in v: print k.filter_expression.var
...
block.super
verb
Run Code Online (Sandbox Code Playgroud)

jat*_*ism 20

您可以直观地检查模板并观察该模板节点列表中是否存在任何"变量节点"对象:

>>> from django.template import Template, Context
>>> t = Template("Django is {{ adjective }} and I {{ verb }} it.")
>>> t.nodelist
[<Text Node: 'Django is '>, <Variable Node: adjective>, <Text Node: ' and I '>, <Variable Node: verb>, <Text Node: ' it.'>]
Run Code Online (Sandbox Code Playgroud)

这些是类型VariableNode,可以直接导入以用于比较.任何Node实例都有一个get_nodes_by_type()可以针对nodelist调用的方法,该节点列表返回该模板的所有类型的节点.例:

>>> from django.template import VariableNode
>>> varnodes = t.nodelist.get_nodes_by_type(VariableNode)
>>> varnodes
[<Variable Node: adjective>, <Variable Node: verb>]
Run Code Online (Sandbox Code Playgroud)

所以现在你有了一个模板变量列表.这将需要更进一步,以提取每个变量的实际名称,而无需在其repr名称上执行愚蠢的字符串切片技巧.

变量名本身存储在filter_expression.token每个VariableNode:

>>> varnodes[0].filter_expression.token
u'adjective'
Run Code Online (Sandbox Code Playgroud)

因此,简单的列表理解会为我们提供模板的所有变量名称:

>>> template_vars = [x.filter_expression.token for x in varnodes]
>>> template_vars
[u'adjective', u'verb']
Run Code Online (Sandbox Code Playgroud)

所以,不是最简单的解决方案,但如果有更好的方法,我不知道它.

额外奖励:功能!!

from django.template import VariableNode
def get_template_vars(t):
   varnodes = t.nodelist.get_nodes_by_type(VariableNode)
   return [x.filter_expression.token for x in varnodes]
Run Code Online (Sandbox Code Playgroud)

好吧,毕竟它并不复杂!

后续编辑:从父模板获取变量

(此后续操作使用更新问题中的信息).

这实际上是复杂的,因为玩具模板的节点列表是单个ExtendsNode(在这种情况下).

>>> toy.nodelist
[<ExtendsNode: extends "mysite/toyparent.html">]
Run Code Online (Sandbox Code Playgroud)

我想在较大的模板中可能有多个ExtendsNode对象.无论如何,如果您检查ExtendsNode并从中提取父模板,您可以将父对象视为与原始示例相同:

>>> enode = toy.nodelist[0]
>>> enode.parent_name
u'mysite/toyparent.html'
>>> parent = enode.get_parent(enode.parent_name)
>>> parent
<django.template.Template object at 0x101c43790>
>>> parent.nodelist.get_nodes_by_type(VariableNode)
[<Variable Node: adjective>]
Run Code Online (Sandbox Code Playgroud)

并且adjective从父模板中提取了您的变量.要对ExtendsNode您执行测试,您可以从django.template.loader_tags以下位置导入类:

>>> from django.template.loader_tags import ExtendsNode
>>> ext = toy.nodelist.get_nodes_by_type(ExtendsNode)
>>> ext
[<ExtendsNode: extends "mysite/toyparent.html">]
Run Code Online (Sandbox Code Playgroud)

因此,您可以针对存在的模板进行一些测试,ExtendsNode然后向后走到父模板,并分别获取这些变量名称.然而,这开始看起来像一堆蠕虫.

例如,如果你这样做:

>>> toy.nodelist.get_nodes_by_type((ExtendsNode, VariableNode))
[<ExtendsNode: extends "mysite/toyparent.html">, <Variable Node: block.super>, <Variable Node: verb>]
Run Code Online (Sandbox Code Playgroud)

现在,你已经得到了ExtendsNodeVariableNode对象,它只是开始变得混乱.那我们做什么?我们是否试图忽略block从这些测试返回的任何变量?我不知道!!

无论如何,这是您想要的信息,但我不认为这是一个实用的解决方案.我坚持认为还有更好的方法.可能值得研究一下您要解决的问题,看看是否还有其他方法可以解决.