Login

IfValueTag

Author:
adurdin
Posted:
March 22, 2007
Language:
Python
Version:
Pre .96
Score:
5 (after 5 ratings)

Don't repeat yourself: when you wish to have a block of html with a variable value, but only if the variable is set, you can do this:

{% ifvalue company.contact.email as email %}
  <h3>Email address</h3>
  <a href='mailto:{{ email }}'>{{ email }}</a>
{% endifvalue %}

Instead of this:

{% if company.contact.email %}
  <h3>Email address</h3>
  <a href='mailto:{{ company.contact.email }}'>{{ company.contact.email }}</a>
{% endifvalue %}

The tags ifvalue and ifnotvalue are provided by this snippet.

If you don't specify as somename, then the variable's value will be assigned to the name "value".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 2 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 2 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 9 months, 2 weeks ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 10 months, 1 week ago
  5. Help text hyperlinks by sa2812 11 months ago

Comments

mawimawi (on March 22, 2007):

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:

def ifnotvalue(parser, token, name="value"):
    [...]
register.tag('ifnotvalue'...)

maybe in this case it might even be possible to add your tag to the core? (wishful thinking, of course)

#

adurdin (on March 29, 2007):

@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:

{% with someobject.somevalue as value %}{% if value %}<p><a href='/'>{{ value }}</a></p>{% endif %}{% endwith %}

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.

#

Please login first before commenting.