Reputation: 6907
I'm trying to use a simple_tag and set a context variable. I'm using the trunk version of django:
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 ''
This doesn't set the variable, but if I do something very similar with @register.tag
it works but the object parameter doesn't pass through...
Thanks!
Upvotes: 21
Views: 16055
Reputation: 1
You can store a context variable with @register.simple_tag which returns simple data instead of returning a complicated Node
class based object as shown below:
# "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 }}
Output:
John 36
In addition, you can store the return value from @register.simple_tag
's person()
to person_info
with as
argument as shown below:
# "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 }}
Output:
John 36
And, you can store a context variable with @register.tag which returns a complicated Node
(class) based object as shown below. *@register.tag
cannot accept takes_context
argument otherwise there is an error and doesn't work with as
argument:
# "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 }}
Output:
John 36
Upvotes: 0
Reputation: 18963
Since Django 1.9, it is possible to store simple_tag
results in a template variable by using the as
argument followed by the variable name:
@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>
Upvotes: 11
Reputation: 12214
You are mixing two approaches here. A simple_tag
is merely a helper function, which cuts down on some boilerplate code and is supposed to return a string. To set context variables, you need (at least with plain django) to write your own tag with a render method.
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)
This may be called like this:
{% do_foo my_object %}
{% do_foo 25 %}
Upvotes: 24