【问题标题】:Django Do Once Custom Template TagDjango Do Once 自定义模板标签
【发布时间】:2011-10-05 12:59:27
【问题描述】:

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

这就是我实现它的方式,但正如您所见,它有点 hackish:

my_partial.html:

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

我的模板.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,使其无法作为全局范围。

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

【问题讨论】:

  • request.session 呢?它不那么骇人听闻。 'once' 模板标签的用例是什么?
  • 我没有使用会话,因为它不想保存超出请求的任何内容。如果我在会话中保存元数据,它将用在请求之外无意义的数据污染我的数据库。我的用例是包含一个模态对话框的 HTML,它通常是隐藏的,并且可以由几个可选的小部件使用,这些小部件可能会或可能不会在页面上使用。我希望每个小部件都包含部分内容,但只执行一次以避免与存在于不同位置的相同 ID 发生冲突。

标签: python django django-templates


【解决方案1】:

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

django for template tag

您很可能应该能够根据您的需要进行这项工作,但是如果它达不到要求,我建议for 模板标签的来源(它是forloop 变量)可能会非常说明你如何实现你想要做的事情。

【讨论】:

  • forloop 无关紧要。我只用它来展示如何多次包含部分内容。这个想法是让标签在第一次使用时记住它,然后禁用它自己。
【解决方案2】:

我最终做的是在上下文中保存一个变量并在节点的渲染方法中检查它:

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__)

        ...

【讨论】:

    猜你喜欢
    • 2021-07-13
    • 2015-01-20
    • 2012-03-15
    • 2015-12-17
    • 2011-03-31
    • 1970-01-01
    • 2010-11-15
    • 2011-12-15
    相关资源
    最近更新 更多