2011-07-14 33 views
1

我想創建一個自定義模板標記,只渲染一段代碼,無論包含它的標記/部分執行多少次。Django做一次自定義模板標記

這是怎麼了,我實現它,但是你可以看到,這是一個有點hackish:

my_partial.html:

{% once mycontent %} 
    this will only show once 
{% endonce%} 

my_template.html:

{% load my_tags %} 
{% for i in list %} 
    {% my_partial %} 
{% endfor %} 

my_tags.py:

@register.inclusion_tag('my_partial.html',takes_context=True) 
def my_partial(context): 
    return dict(arbitrary extra data) 

@register.tag(name="once") 
def do_once(parser, token): 
    try: 
     # Splitting by None == splitting by spaces. 
     tag_name, var_name = token.contents.split(None, 1) 
    except ValueError: 
     raise template.TemplateSyntaxError("%r tag requires arguments" % token.contents.split()[0]) 
    nodelist = parser.parse(('endonce',)) 
    parser.delete_first_token() 
    return DoOnceNode(nodelist, var_name) 

class DoOnceNode(template.Node): 
    def __init__(self, nodelist, var_name): 
     self.nodelist = nodelist 
     self.var_name = '_do_once_'+var_name 
    def render(self, context): 
     request = context['request'] 

     # Make request.GET mutable. 
     request.GET = dict(request.GET) 

     if self.var_name in request.GET: 
      return '' 
     else: 
      request.GET[self.var_name] = 1 
      return self.nodelist.render(context) 

具體來說,我使用request.GET字典作爲可變全局範圍。這很破爛,顯然不是請求對象設計的目的,但它起作用。

理想情況下,我想使用類似上下文的東西,但我發現它不會在對此標記的調用之間共享。即self.var_name in context總是False,使其作爲全局範圍無用。

爲什麼不共享上下文以共享請求的方式?有沒有辦法讓它真正共享,還是有一些其他對象可以用來在請求中存儲全局可訪問的變量?

+0

怎麼樣的request.session?這是一個少一點hackish。 「一次」模板標籤有什麼用途? – Tiago

+0

我沒有使用會話,因爲它不想保存超出請求的任何內容。如果我在會話中保存元數據,將會在請求之外使用無意義的數據污染我的數據庫。我的使用案例是爲通常隱藏的模式對話框添加HTML,並且可能會使用多個可選的小部件,這些小部件可能會或可能不會在頁面上使用。我希望每個小部件都包含部分內容,但只做一次,以避免與存在於不同位置的相同ID發生衝突。 – Cerin

回答

0

我不完全確定你需要完成什麼,或者如果你的方法確實是最好的方法,但是我建議你先看看forloop.first變量,然後再走這條路。你的做法似乎笨拙充其量一眼,但我可能是錯的,因爲我不知道的情況

django for template tag

最有可能的,你應該能夠使這項工作您需要的具體細節,然而,如果它不足,我建議for模板標籤(以及它的forloop變量)的來源可能會說明你如何實現你想要做的事情。

+1

forloop是無關緊要的。我只用它來顯示一個部分可能被包含多次。這個想法是讓標籤在第一次使用時記住,並在此後關閉。 – Cerin

0

我最終什麼事做的是保存上下文中的變量,並在節點的渲染方法檢查的是:

class CustomNode(template.Node): 
    def render(self, context: dict) -> str: 
     context['already_rendered'] = context.get('already_rendered', set()) 

     if self.__class__ in context['already_rendered']: 
      return '' 

     context['already_rendered'].add(self.__class__) 

     ...