【问题标题】:Query a template for the variables it needs?查询模板以获取它需要的变量?
【发布时间】:2010-12-23 00:49:20
【问题描述】:

我希望能够从文件中实例化模板(大概使用 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%}

toychild.html:

{% extends "toyparent.html" %}

{%block base_results%}
    {{block.super}}
    I {{verb}} it.
{%endblock base_results %}

然后我加载子模板:

>>> toy=django.template.loader.get_template('toychild.html')

这会正确渲染:

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

但我无法从中获取两个变量:

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

【问题讨论】:

    标签: django variables django-templates


    【解决方案1】:

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

    >>> 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.'>]
    

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

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

    所以现在您有了模板的变量列表。这需要进一步提取每个变量的实际名称,而不是对其repr 名称执行愚蠢的字符串切片技巧。

    对于每个VariableNode,变量名本身存储在filter_expression.token中:

    >>> varnodes[0].filter_expression.token
    u'adjective'
    

    所以一个简单的列表推导式就可以得到模板的所有变量名:

    >>> template_vars = [x.filter_expression.token for x in varnodes]
    >>> template_vars
    [u'adjective', u'verb']
    

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

    奖励:一个函数!!

    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]
    

    好吧,毕竟没那么复杂!

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

    (本次跟进使用更新问题中的信息)。

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

    >>> toy.nodelist
    [<ExtendsNode: extends "mysite/toyparent.html">]
    

    我想在较大的模板中可能有多个 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>]
    

    还有从父模板中提取的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">]
    

    因此,您可以针对模板进行一些测试以检查是否存在 ExtendsNode,然后返回到父模板并单独获取这些变量名称。然而,这开始看起来像一罐蠕虫。

    例如,如果您要这样做:

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

    现在你已经有了ExtendsNodeVariableNode 对象,它开始变得混乱。那我们怎么办?我们是否尝试忽略从此类测试返回的任何block 变量?不知道!!

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

    【讨论】:

    • 谢谢 - 这很接近,但似乎不能正常继承 - 请参阅上面的扩展问题描述。
    • 啊,你是对的。我什至没有考虑过模板扩展。让我四处看看,看看我能不能弄明白。
    • 哇,很棒的研究和信息。 +1
    • 这个模板树遍历器可能会有所帮助:github.com/edoburu/django-template-analyzer
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多