2009-12-03 24 views
12

我想能夠從文件中實例化模板(大概使用django.template.loader.get_template(filename)),然後確定應該在傳遞的任何上下文中定義的變量集。查詢它需要的變量的模板?

我以爲會有一個模板對象的方法,但似乎並沒有。

我閱讀文檔,我發現最接近的是這樣的:

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

這表明要管理界面看到與給定視圖相關聯的所有變量。

我不想通過管理界面,因爲我想以編程方式執行此操作 - 我正在嘗試編寫測試。

我使用Django版本(1,0,2, '最後',0)

更新時間:

我試圖SYNACK的答案,發現(與filter_expression filter_expression.token更換.var,以獲取變量的實際名稱而不用標籤等),它返回在模板中本地定義的變量,但不適用於在其擴展的父級中定義的變量。

因此,舉例來說,假設我有模板的兩個文件:

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 

回答

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

這些類型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>] 

所以現在你有一個模板變量的列表。這將需要進一步提取每個變量的實際名稱,而不要在其名稱上使用愚蠢的字符串切片技巧。

變量名稱本身存儲在filter_expression.token每個VariableNode

>>> 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變量?我不知道!!

無論如何,這是你想要的信息,但我不認爲這是一個實際的解決方案。我堅持認爲還是可能有更好的辦法。可能值得研究你想要解決的問題,看看你是否可以採取另一種方法。

+0

謝謝 - 這很接近,但對於繼承似乎不能正常工作 - 請參閱上面的擴展問題描述。 – 2009-12-04 16:43:56

+1

啊,你說得對。我甚至沒有考慮過模板擴展。讓我捅一下,看看我能否弄清楚。 – jathanism 2009-12-04 19:16:55

+1

哇,很好的研究和信息。 +1 – 2009-12-05 05:13:47