Django

Code

Show
Ignore:
Timestamp:
11/24/08 16:01:48 (2 months ago)
Author:
jacob
Message:

Fixed #6398: added an optional {% empty %} clause to the {% for %} template tag. The contents of this clause are rendered if the list iterated over turns out to be empty. Thanks, Jannis Leidel.

Astute readers will notice that the patch originally called this default; after consideration I decided that empty is a very slightly better color for this particular bikeshed.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/template/defaulttags.py

    r8716 r9530  
    8484 
    8585class ForNode(Node): 
    86     def __init__(self, loopvars, sequence, is_reversed, nodelist_loop): 
     86    def __init__(self, loopvars, sequence, is_reversed, nodelist_loop, nodelist_empty=None): 
    8787        self.loopvars, self.sequence = loopvars, sequence 
    8888        self.is_reversed = is_reversed 
    8989        self.nodelist_loop = nodelist_loop 
     90        if nodelist_empty is None: 
     91            self.nodelist_empty = NodeList() 
     92        else: 
     93            self.nodelist_empty = nodelist_empty 
    9094 
    9195    def __repr__(self): 
     
    98102        for node in self.nodelist_loop: 
    99103            yield node 
     104        for node in self.nodelist_empty: 
     105            yield node 
    100106 
    101107    def get_nodes_by_type(self, nodetype): 
     
    104110            nodes.append(self) 
    105111        nodes.extend(self.nodelist_loop.get_nodes_by_type(nodetype)) 
     112        nodes.extend(self.nodelist_empty.get_nodes_by_type(nodetype)) 
    106113        return nodes 
    107114 
    108115    def render(self, context): 
    109         nodelist = NodeList() 
    110116        if 'forloop' in context: 
    111117            parentloop = context['forloop'] 
     
    122128            values = list(values) 
    123129        len_values = len(values) 
     130        if len_values < 1: 
     131            return self.nodelist_empty.render(context) 
     132        nodelist = NodeList() 
    124133        if self.is_reversed: 
    125134            values = reversed(values) 
     
    611620        {% endfor %} 
    612621 
     622    The ``for`` tag can take an optional ``{% empty %}`` clause that will 
     623    be displayed if the given array is empty or could not be found:: 
     624 
     625        <ul> 
     626          {% for athlete in athlete_list %} 
     627            <li>{{ athlete.name }}</li> 
     628          {% empty %} 
     629            <li>Sorry, no athletes in this list.</li> 
     630          {% endfor %} 
     631        <ul> 
     632         
     633    The above is equivalent to -- but shorter, cleaner, and possibly faster 
     634    than -- the following:: 
     635     
     636        <ul> 
     637          {% if althete_list %} 
     638            {% for athlete in athlete_list %} 
     639              <li>{{ athlete.name }}</li> 
     640            {% endfor %} 
     641          {% else %} 
     642            <li>Sorry, no athletes in this list.</li> 
     643          {% endif %} 
     644        </ul> 
     645 
    613646    The for loop sets a number of variables available within the loop: 
    614647 
     
    647680 
    648681    sequence = parser.compile_filter(bits[in_index+1]) 
    649     nodelist_loop = parser.parse(('endfor',)) 
    650     parser.delete_first_token() 
    651     return ForNode(loopvars, sequence, is_reversed, nodelist_loop) 
     682    nodelist_loop = parser.parse(('default', 'endfor',)) 
     683    token = parser.next_token() 
     684    if token.contents == 'default': 
     685        nodelist_default = parser.parse(('endfor',)) 
     686        parser.delete_first_token() 
     687    else: 
     688        nodelist_default = None 
     689    return ForNode(loopvars, sequence, is_reversed, nodelist_loop, nodelist_default) 
    652690do_for = register.tag("for", do_for) 
    653691