【问题标题】:Postprocess django template nodes to combine tags before rendering在渲染之前对 django 模板节点进行后处理以组合标签
【发布时间】:2014-01-17 08:31:30
【问题描述】:

在 django 1.6+ 中渲染模板之前,我需要组合连续的自定义模板标签。这些标签可以是来自选定的“兼容”标签列表的相同或不同的标签。

我试图在调用render(context) 之前遍历模板nodelist。此循环将组合兼容的连续节点,但是我无法弄清楚如何在模板上自动调用一个函数,然后再用上下文呈现它。

我看过

1) 中间件 - 似乎没有人可以访问已编译的模板节点列表
2) 自定义模板类 - 打破像renderrender_to_response这样的快捷方式
3) 在视图中的模板上直接调用函数 - 与上述相同的问题

对如何实现这一点有任何想法吗?


一点背景

基本思想是让不同的模板标签“一起渲染”,例如在一个简化的例子中:

{% tag_one "1A" "1B" %}{% tag_two "2A" %}

而不是呈现为两个单独的块:

[ 1A 1B ][ 2A ]

这将呈现为单个标签块:

[ 1A 1B 2A ]

标签的渲染功能背后还有比这更多的逻辑,但这里不相关......

【问题讨论】:

  • 我的回答能满足您的要求吗?有什么可以改进的吗?

标签: python django templates


【解决方案1】:

您可以使用这个 sn-p: Capture template output as a variable 并定义一个 new filter 来删除“][”或其中的任何内容。

示例(在您的templatetags 目录中的文件中):

from django import template
from django.template.defaultfilters import stringfilter

register = template.Library()

@register.tag(name='captureas')
def do_captureas(parser, token):
    try:
        tag_name, args = token.contents.split(None, 1)
    except ValueError:
        raise template.TemplateSyntaxError("'captureas' node requires a variable name.")
    nodelist = parser.parse(('endcaptureas',))
    parser.delete_first_token()
    return CaptureasNode(nodelist, args)

class CaptureasNode(template.Node):
    def __init__(self, nodelist, varname):
        self.nodelist = nodelist
        self.varname = varname

    def render(self, context):
        output = self.nodelist.render(context)
        context[self.varname] = output
        return ''


@register.filter(name='join_my_tags')
@stringfilter
def join_my_tags(text):
    return text.replace(' ][ ', '')

用法(在您看来):

{% captureas my_tags %}{% tag_one "1A" "1B" %}{% tag_two "2A" %}{% endcaptureas %}
{{my_tags|join_my_tags}}

未经测试的替代方法:它不需要任何模板标签,但如果您想避免附带影响(例如弄乱您的 javascript 代码),您必须在替换时非常有选择性。它与您的尝试类似,但在渲染之后执行,而不是之前。

以这种方式修改您的视图:

from django.shortcuts import render

def index(request):
    myresponse = render(request, 'index.html')  # add your context object if you need it
    return HttpResponse(myresponse.content.replace(' ][ ', '')) # you may eventually use regex or eventually even a full html parser (!) but please take performances in account :)

【讨论】:

  • 感谢 furins - 一个很好的实用答案。我希望模板标签上的内容更轻一些 - 即不需要任何额外的标记。我想知道我是否可以使用解析器“窥视”?
  • 在这种情况下,您可以在返回 HTTPResponse 之前对其进行解析和操作,但在我看来,这种方法会给您的服务器增加额外的工作
  • 我已经编辑了我的答案,以更具体的形式为您提供替代方法。我没有时间测试它,但它应该是您代码中的一个简单替换,因此您可以尝试一下。
【解决方案2】:

您可以在提供给模板标签的解析器中“窥视”。例如以下使用parser.next_token() 来检查接下来的几个TemplateNodes 以查看它们是否兼容。

def my_tag(parser, token):
    parse_me = [token]

    # the following lines check if there are any additional nodes
    # that we should combine and adds them to a list for processing 
    if parser.tokens:
        while parser.tokens[0].token_type == 2 and parser.tokens[0].content[0:3] == 'my_':
            parse_me.append(parser.next_token())

    contents = ""
    for tok in parse_me:
        # apply some logic to combine the nodes
        contents += tok.contents 

    return MyCustomNode(contents)

【讨论】:

    猜你喜欢
    • 2015-11-14
    • 2013-09-13
    • 2011-11-29
    • 2020-11-29
    • 2017-02-11
    • 2022-01-15
    • 2015-09-21
    • 2014-12-08
    • 2011-12-01
    相关资源
    最近更新 更多