我正在尝试创建一个自定义模板标记,该标记只会渲染一次代码块,而不管执行包含它的标记/部分的次数。
这就是我实现它的方式,但正如你所看到的,它有点像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字典作为可变的全局范围。它是hackish,显然不是请求对象的设计目的,但它可以工作。
理想情况下,我想使用类似上下文的内容,但我发现在调用此标记之间不会共享它。即self.var_name in context
始终为False,使其无法用作全局范围。
为什么上下文共享的方式与共享请求的方式不同?有没有办法使它真正共享,还是有一些其他对象可以用来在请求中存储全局可访问的变量?
答案 0 :(得分:1)
我不确定你需要完成什么,或者你的方法确实是最好的方法,但我建议你在这条路走得太远之前先看看forloop.first
变量。你的方法一目了然似乎很尴尬,但我可能是错的,因为我不知道具体情况
最有可能的是,您应该能够根据自己的需要开展此工作,但如果不足,我建议for
模板代码(及其forloop
变量)的来源可能说明你如何实现你想要做的事情。
答案 1 :(得分:0)
我最终做的是在上下文中保存变量并在Node的render方法中检查它:
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__)
...