from django.template import Library
from django.template import FilterExpression, Node, NodeList
from django.template import TemplateSyntaxError, VariableDoesNotExist
register = Library()
def do_ifvalue(parser, token, name, negate=False):
bits = list(token.split_contents())
if len(bits) != 2 and len(bits) != 4:
raise TemplateSyntaxError, "%r takes one or three arguments" % bits[0]
tagname, variable = tuple(bits)[:2]
if len(bits) == 4:
if bits[2] != "as":
raise TemplateSyntaxError, "%r with three arguments must be 'value as name'" % tagname
name = bits[3]
end_tag = 'end' + tagname
nodelist_true = parser.parse(('else', end_tag))
token = parser.next_token()
if token.contents == 'else':
nodelist_false = parser.parse((end_tag,))
parser.delete_first_token()
else:
nodelist_false = NodeList()
expr = FilterExpression(variable, parser)
return IfValueNode(expr, name, nodelist_true, nodelist_false, negate)
@register.tag
def ifvalue(parser, token, name="value"):
"""
Output the contents of the block if the argument is true, assigning
the value of the argument to a context variable ("value" by default).
Examples::
{% ifvalue user.name %}
{{ value }}
...
{% else %}
...
{% endifvalue %}
{% ifvalue user.name as username %}
{{ username }}
...
{% else %}
...
{% endifvalue %}
"""
return do_ifvalue(parser, token, name, False)
@register.tag
def ifnotvalue(parser, token, name="value"):
"""Output the contents of the block if the argument is false. See ifvalue."""
return do_ifvalue(parser, token, name, True)
class IfValueNode(Node):
def __init__(self, var, name, nodelist_true, nodelist_false, negate):
self.var = var
self.name = name
self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
self.negate = negate
def __repr__(self):
return "<IfValueNode>"
def render(self, context):
val = self.var.resolve(context, ignore_failures=True)
context[self.name] = val
if (self.negate and not val) or (not self.negate and val):
return self.nodelist_true.render(context)
return self.nodelist_false.render(context)
def get_nodes_by_type(self, nodetype):
nodes = []
if isinstance(self, nodetype):
nodes.append(self)
nodes.extend(self.nodelist_true.get_nodes_by_type(nodetype))
nodes.extend(self.nodelist_false.get_nodes_by_type(nodetype))
return nodes
Comments
I like it a lot! (but it is unneccessarily python2.4-code and incompatible with python2.3)
you might consider not using decorators, but instead the old python style:
maybe in this case it might even be possible to add your tag to the core? (wishful thinking, of course)
#
I suggest that you see snippet #9, it can save a value of python expression to a variable.
#
I created a
{% with %}tag to do a similar thing to this, but a bit more generic than tying it to anif: snippet #132#
@limodou, SmileyChris -- I'd still be using this tag even if I had the expr or with tags; I don't want to have to do:
The assignation of the value to another name is an adjunct to the purpose of entirely omitting the html elements if their contained value is empty.
--
I've just updated the snippet to support filters; in my templatetag naïveté I'd not known how to this initially.
#