Django的simple_tag和设置上下文变量

21

我正在尝试使用simple_tag并设置上下文变量。我正在使用Django的trunk版本:

from django import template

@register.simple_tag(takes_context=True)
def somefunction(context, obj):   
    return set_context_vars(obj)

class set_context_vars(template.Node):
    def __init__(self, obj):
        self.object = obj
    
    def render(self, context):
        context['var'] = 'somevar'
        return ''

这不会设置变量,但如果我使用类似于 @register.tag 的方法就能够工作,但是对象参数无法通过...

谢谢!

3个回答

24
你在这里混淆了两种方法。一个简单标签(simple_tag)只是一个辅助函数,可以减少一些样板代码并且应该返回一个字符串。要设置上下文变量,你需要(至少在纯 Django 中)自己编写具有渲染方法的标签
from django import template

register = template.Library()


class FooNode(template.Node):

    def __init__(self, obj):
        # saves the passed obj parameter for later use
        # this is a template.Variable, because that way it can be resolved
        # against the current context in the render method
        self.object = template.Variable(obj)

    def render(self, context):
        # resolve allows the obj to be a variable name, otherwise everything
        # is a string
        obj = self.object.resolve(context)
        # obj now is the object you passed the tag

        context['var'] = 'somevar'
        return ''


@register.tag
def do_foo(parser, token):
    # token is the string extracted from the template, e.g. "do_foo my_object"
    # it will be splitted, and the second argument will be passed to a new
    # constructed FooNode
    try:
        tag_name, obj = token.split_contents()
    except ValueError:
        raise template.TemplateSyntaxError, "%r tag requires exactly one argument" % token.contents.split()[0]
    return FooNode(obj)

这可以这样调用:
{% do_foo my_object %}
{% do_foo 25 %}

6
请注意,Django的开发版本包括assignment_tag,它类似于simple_tag但实现了as variablename功能:https://docs.djangoproject.com/en/dev/howto/custom-template-tags/#assignment-tags - Jordan Reiter
哦,我以前从未遇到过 assignment_tag。 很好。给未来的读者更新一下:assignment_tag 可在 Django 版本>= 1.4 中使用(我假设在上面的评论时还在开发中)。 - chucksmash
3
现在可以使用“as变量”保存simple_tag的结果,而assignment_tag正在被弃用。 - mehmet
1
从文档中得知:自版本1.9起,assignment_tag已被弃用。simple_tag现在可以将结果存储在模板变量中,应该使用它来代替。https://docs.djangoproject.com/en/1.11/howto/custom-template-tags/#assignment-tags - highpost

10
自 Django 1.9 开始,可以使用 as 参数并指定变量名,将simple_tag的结果存储在模板变量中:
@register.simple_tag
def current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

{% current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>

4
谢谢,我已经搜寻了好几个小时!这对于Django 3.0有效。 - VicenteC
1
很高兴能帮到你 :)! - mrts

0

您可以使用@register.simple_tag存储上下文变量,该变量返回简单数据而不是返回基于Node类的复杂对象,如下所示:

# "custom_tags.py"

from django.template import Library

register = Library()

@register.simple_tag(takes_context=True)
def person(context):
    context["name"] = "John"
    context["age"] = 36
    return ""

# "index.html"

{% load custom_tags %}

{% person %}
{{ name }} {{ age }}

输出:

John 36

此外,您可以使用as参数将从@register.simple_tagperson()返回的值存储到person_info中,如下所示:
# "custom_tags.py"

@register.simple_tag(takes_context=True)
def person(context):
    return "John 36"

# "index.html"

{% load custom_tags %}

{% person as person_info %}
{{ person_info }}

输出:

John 36

而且,您可以使用@register.tag存储上下文变量,该变量返回一个基于Node(类)的复杂对象,如下所示。*如果@register.tag不能接受takes_context参数,则会出现错误,并且无法与as参数一起使用:

# "custom_tags.py"

from django.template import Library, Node

register = Library()

@register.tag
def person(parser, token):
    return PersonNode()

class PersonNode(Node):
    def __init__(self):
        pass

    def render(self, context):
        context["name"] = "John"
        context["age"] = 36
        return ""

# "index.html"

{% load custom_tags %}

{% person %}
{{ name }} {{ age }}

输出:

John 36

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接