Django做一次自定义模板标记

时间:2011-07-14 16:57:21

标签: python django django-templates

我正在尝试创建一个自定义模板标记,该标记只会渲染一次代码块,而不管执行包含它的标记/部分的次数。

这就是我实现它的方式,但正如你所看到的,它有点像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,使其无法用作全局范围。

为什么上下文共享的方式与共享请求的方式不同?有没有办法使它真正共享,还是有一些其他对象可以用来在请求中存储全局可访问的变量?

2 个答案:

答案 0 :(得分:1)

我不确定你需要完成什么,或者你的方法确实是最好的方法,但我建议你在这条路走得太远之前先看看forloop.first变量。你的方法一目了然似乎很尴尬,但我可能是错的,因为我不知道具体情况

django for template tag

最有可能的是,您应该能够根据自己的需要开展此工作,但如果不足,我建议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__)

        ...