Ticket #3791: if_templatetag.diff

File if_templatetag.diff, 5.3 KB (added by nowell strite, 8 years ago)

Patch for django's If templatetag

  • django/template/defaulttags.py

     
    66from django.conf import settings
    77import sys
    88
     9# For Python 2.3
     10if not hasattr(__builtins__, 'set'):
     11    from sets import Set as set
     12
    913register = Library()
    1014
    1115class CommentNode(Node):
     
    176180        return self.nodelist_false.render(context)
    177181
    178182class IfNode(Node):
    179     def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
    180         self.bool_exprs = bool_exprs
     183    def __init__(self, expression, variables, nodelist_true, nodelist_false):
     184        self.expression = expression
     185        self.variables = variables
    181186        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
    182         self.link_type = link_type
    183187
    184188    def __repr__(self):
    185189        return "<If node>"
     
    199203        return nodes
    200204
    201205    def render(self, context):
    202         if self.link_type == IfNode.LinkTypes.or_:
    203             for ifnot, bool_expr in self.bool_exprs:
    204                 try:
    205                     value = bool_expr.resolve(context, True)
    206                 except VariableDoesNotExist:
    207                     value = None
    208                 if (value and not ifnot) or (ifnot and not value):
    209                     return self.nodelist_true.render(context)
     206        variable_context = {}
     207        expression = self.expression
     208        for variable in self.variables:
     209            try:
     210                value = variable.resolve(context, True)
     211            except VariableDoesNotExist:
     212                value = None
     213
     214            context_name = 'var%s' % len(variable_context)
     215            expression = re.sub(r'(?<![\w\.\"\'])%s(?![\w\.\"\'])' % re.escape(variable.token), context_name, expression)
     216            variable_context[context_name] = value
     217        try:
     218            resultant = eval(expression, variable_context)
     219        except:
     220            resultant = False
     221        if not resultant:
    210222            return self.nodelist_false.render(context)
    211         else:
    212             for ifnot, bool_expr in self.bool_exprs:
    213                 try:
    214                     value = bool_expr.resolve(context, True)
    215                 except VariableDoesNotExist:
    216                     value = None
    217                 if not ((value and not ifnot) or (ifnot and not value)):
    218                     return self.nodelist_false.render(context)
    219             return self.nodelist_true.render(context)
     223        return self.nodelist_true.render(context)
    220224
    221     class LinkTypes:
    222         and_ = 0,
    223         or_ = 1
    224 
    225225class RegroupNode(Node):
    226226    def __init__(self, target, expression, var_name):
    227227        self.target, self.expression = target, expression
     
    622622            There are no athletes, or there are some coaches.
    623623        {% endif %}
    624624
    625     For simplicity, ``if`` tags do not allow ``and`` clauses. Use nested ``if``
    626     tags instead::
     625    Regular python conditional syntax and comparisons are avaialble, however,
     626    variables must use the Django Template "." syntax to access dict keys and
     627    array indicies.
    627628
    628         {% if athlete_list %}
    629             {% if coach_list %}
    630                 Number of athletes: {{ athlete_list|count }}.
    631                 Number of coaches: {{ coach_list|count }}.
    632             {% endif %}
    633         {% endif %}
     629        {% if ("Jacob" in athelete_list and "Mike" not in athelete_list) or athelete_list.count > 2  %}
     630             Jacob is an athelete and Mikey is not OR there are more than 2 atheletes.
     631        {% endif %}
    634632    """
    635     bits = token.contents.split()
     633    bits = token.contents.split(None, 1)
    636634    del bits[0]
    637     if not bits:
     635    expression = bits[0]
     636    variables = set([ parser.compile_filter(x) for x in re.findall('[\w\.]+', expression) if x not in ('and', 'or', 'not', 'in') ])
     637    if not variables:
    638638        raise TemplateSyntaxError, "'if' statement requires at least one argument"
    639     # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
    640     bitstr = ' '.join(bits)
    641     boolpairs = bitstr.split(' and ')
    642     boolvars = []
    643     if len(boolpairs) == 1:
    644         link_type = IfNode.LinkTypes.or_
    645         boolpairs = bitstr.split(' or ')
    646     else:
    647         link_type = IfNode.LinkTypes.and_
    648         if ' or ' in bitstr:
    649             raise TemplateSyntaxError, "'if' tags can't mix 'and' and 'or'"
    650     for boolpair in boolpairs:
    651         if ' ' in boolpair:
    652             try:
    653                 not_, boolvar = boolpair.split()
    654             except ValueError:
    655                 raise TemplateSyntaxError, "'if' statement improperly formatted"
    656             if not_ != 'not':
    657                 raise TemplateSyntaxError, "Expected 'not' in if statement"
    658             boolvars.append((True, parser.compile_filter(boolvar)))
    659         else:
    660             boolvars.append((False, parser.compile_filter(boolpair)))
     639
    661640    nodelist_true = parser.parse(('else', 'endif'))
    662641    token = parser.next_token()
    663642    if token.contents == 'else':
     
    665644        parser.delete_first_token()
    666645    else:
    667646        nodelist_false = NodeList()
    668     return IfNode(boolvars, nodelist_true, nodelist_false, link_type)
     647    return IfNode(expression, variables, nodelist_true, nodelist_false)
    669648do_if = register.tag("if", do_if)
    670649
    671650#@register.tag
Back to Top