Ticket #3075: ifequal.diff

File ifequal.diff, 14.2 KB (added by Will McCutchen <mccutchen@…>, 8 years ago)

First patch, against r4991

  • django/template/defaulttags.py

     
    154154            return ''
    155155
    156156class IfEqualNode(Node):
    157     def __init__(self, var1, var2, nodelist_true, nodelist_false, negate):
    158         self.var1, self.var2 = var1, var2
     157    def __init__(self, varpairs, nodelist_true, nodelist_false, link_type, negate):
     158        self.varpairs = varpairs
    159159        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false
     160        self.link_type = link_type
    160161        self.negate = negate
    161162
    162163    def __repr__(self):
    163164        return "<IfEqualNode>"
     165   
     166    def evaluate(self, val1, val2):
     167        if (self.negate and val1 == val2) or (not self.negate and val1 != val2):
     168            return False
     169        else:
     170            return True
    164171
    165172    def render(self, context):
    166         try:
    167             val1 = resolve_variable(self.var1, context)
    168         except VariableDoesNotExist:
    169             val1 = None
    170         try:
    171             val2 = resolve_variable(self.var2, context)
    172         except VariableDoesNotExist:
    173             val2 = None
    174         if (self.negate and val1 != val2) or (not self.negate and val1 == val2):
     173        values = []
     174        for var1, var2 in self.varpairs:
     175            try:
     176                val1 = resolve_variable(var1, context)
     177            except VariableDoesNotExist:
     178                val1 = None
     179            try:
     180                val2 = resolve_variable(var2, context)
     181            except VariableDoesNotExist:
     182                val2 = None
     183            values.append((val1, val2))
     184
     185        if self.link_type == IfNode.LinkTypes.and_ or self.link_type is None:
     186            for val1, val2 in values:
     187                if not self.evaluate(val1, val2):
     188                    return self.nodelist_false.render(context)
    175189            return self.nodelist_true.render(context)
    176         return self.nodelist_false.render(context)
     190       
     191        else: # OR clause
     192            for val1, val2 in values:
     193                if self.evaluate(val1, val2):
     194                    return self.nodelist_true.render(context)
     195            return self.nodelist_false.render(context)
    177196
    178197class IfNode(Node):
    179198    def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type):
     
    577596        nodelist_false = NodeList()
    578597    return IfEqualNode(bits[1], bits[2], nodelist_true, nodelist_false, negate)
    579598
     599def do_ifequal(parser, token, negate):
     600    bits = list(token.split_contents())
     601    tag_name = bits[0]
     602    end_tag = 'end%s' % tag_name
     603    del bits[0]
     604    num_bits = len(bits)
     605   
     606    if num_bits < 2:
     607        raise TemplateSyntaxError, "'%s' statement requires at least two arguments" % tag_name
     608    if 'and' in bits and 'or' in bits:
     609        raise TemplateSyntaxError, "'%s' statement cannot contain both 'and' and 'or'" % tag_name
     610    if bits[-1] in ('and', 'or'):
     611        raise TemplateSyntaxError, "'%s' statement improperly formatted" % tag_name
     612   
     613    varpairs = []
     614    link_type = None
     615    if num_bits == 2:
     616        varpairs.append(tuple(bits))
     617    else:
     618        if 'and' in bits:
     619            link_type = IfNode.LinkTypes.and_
     620        elif 'or' in bits:
     621            link_type = IfNode.LinkTypes.or_
     622        else:
     623            raise TemplateSyntaxError, "'%s' statement expected either 'and' or 'or' clause" % tag_name
     624       
     625        # We have at least one 'and' or 'or' clause for a minimum of 5 bits, with each
     626        # additional clause adding 3 bits.       
     627        if num_bits < 5 or (num_bits + 1) % 3 != 0:
     628            raise TemplateSyntaxError, "'%s' statement improperly formatted" % tag_name
     629       
     630        bits = [bit for bit in bits if bit not in ('and', 'or')]
     631        for i, bit in enumerate(bits):
     632            if (i + 1) % 2 == 0:
     633                varpairs.append((bits[i-1], bit))
     634   
     635    nodelist_true = parser.parse(('else', end_tag))
     636    token = parser.next_token()
     637    if token.contents == 'else':
     638        nodelist_false = parser.parse((end_tag,))
     639        parser.delete_first_token()
     640    else:
     641        nodelist_false = NodeList()
     642    return IfEqualNode(varpairs, nodelist_true, nodelist_false, link_type, negate)
     643
     644
    580645#@register.tag
    581646def ifequal(parser, token):
    582647    """
    583     Output the contents of the block if the two arguments equal each other.
     648    Output the contents of the block if the two arguments equal each other. May
     649    contain either 'and' or 'or' clauses, but not both.
    584650
    585651    Examples::
    586652
     
    593659        {% else %}
    594660            ...
    595661        {% endifnotequal %}
     662       
     663        {% ifequal user.id comment.user_id or user.id 0 }
     664            ...
     665        {% endifequal }
    596666    """
    597667    return do_ifequal(parser, token, False)
    598668ifequal = register.tag(ifequal)
  • tests/regressiontests/templates/tests.py

     
    414414            'ifequal-numeric10': ('{% ifequal x -5 %}yes{% endifequal %}', {'x': -5}, 'yes'),
    415415            'ifequal-numeric11': ('{% ifequal x -5.2 %}yes{% endifequal %}', {'x': -5.2}, 'yes'),
    416416            'ifequal-numeric12': ('{% ifequal x +5 %}yes{% endifequal %}', {'x': 5}, 'yes'),
     417           
     418            # AND CLAUSES
     419            'ifequal-and01': ('{% ifequal x 5 and y 10 %}yes{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
     420            'ifequal-and02': ('{% ifequal x 5 and y 10 %}yes{% endifequal %}', {'x': 5}, ''),
     421            'ifequal-and03': ('{% ifequal x 5 and y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
     422            'ifequal-and04': ('{% ifequal x 5 and y 10 %}yes{% else %}no{% endifequal %}', {'x': 5}, 'no'),
     423            'ifequal-and05': ('{% ifequal x 4 and y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'no'),
     424            'ifequal-and06': ('{% ifequal x 5 and y 9 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'no'),
     425            'ifequal-and07': ('{% ifequal x "test man" and y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
     426            'ifequal-and08': ('{% ifequal x "test man" and y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
     427            'ifequal-and09': ('{% ifequal x "best man" and y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
     428            'ifequal-and10': ('{% ifequal x "best man" and y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
     429            'ifequal-and11': ('{% ifequal x 5 and y 10 and z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
     430            'ifequal-and12': ('{% ifequal x 5 and y 0 and z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'no'),
     431            'ifequal-and13': ('{% ifequal x 5 and y 10 and z 0 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'no'),
     432            'ifequal-and14': ('{% ifequal x a and y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 10}, 'yes'),
     433            'ifequal-and15': ('{% ifequal x a and y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 11}, 'no'),
     434           
     435            # OR CLAUSES
     436            'ifequal-or01': ('{% ifequal x 5 or y 9 %}yes{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
     437            'ifequal-or02': ('{% ifequal x 5 or y 9 %}yes{% endifequal %}', {'x': 5}, 'yes'),
     438            'ifequal-or03': ('{% ifequal x 4 or y 9 %}yes{% endifequal %}', {'x': 5}, ''),
     439            'ifequal-or04': ('{% ifequal x 5 or y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
     440            'ifequal-or05': ('{% ifequal x 4 or y 10 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'yes'),
     441            'ifequal-or06': ('{% ifequal x 5 or y 10 %}yes{% else %}no{% endifequal %}', {'x': 5}, 'yes'),
     442            'ifequal-or07': ('{% ifequal x 4 or y 9 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10}, 'no'),
     443            'ifequal-or08': ('{% ifequal x "test man" or y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
     444            'ifequal-or09': ('{% ifequal x "test man" or y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
     445            'ifequal-or10': ('{% ifequal x "best man" or y "good job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "yes"),
     446            'ifequal-or11': ('{% ifequal x "best man" or y "bad job" %}yes{% else %}no{% endifequal %}', {'x': 'test man', 'y': 'good job'}, "no"),
     447            'ifequal-or12': ('{% ifequal x 5 or y 10 or z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
     448            'ifequal-or13': ('{% ifequal x 0 or y 10 or z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
     449            'ifequal-or14': ('{% ifequal x 5 or y 0 or z 15 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
     450            'ifequal-or15': ('{% ifequal x 5 or y 10 or z 0 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'yes'),
     451            'ifequal-or16': ('{% ifequal x 0 or y 0 or z 0 %}yes{% else %}no{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, 'no'),
     452            'ifequal-or16': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 10}, 'yes'),
     453            'ifequal-or17': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 6, 'y': 10, 'b': 10}, 'yes'),
     454            'ifequal-or18': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 5, 'y': 10, 'b': 11}, 'yes'),
     455            'ifequal-or19': ('{% ifequal x a or y b %}yes{% else %}no{% endifequal %}', {'x': 5, 'a': 6, 'y': 10, 'b': 11}, 'no'),
     456           
     457            # AND and OR raises a TemplateSyntaxError
     458            'ifequal-error01': ('{% ifequal x 5 and y 10 or z 15 %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     459            'ifequal-error02': ('{% ifequal x 5 or y 10 and z 15 %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     460            'ifequal-error03': ('{% ifequal x 5 and %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     461            'ifequal-error04': ('{% ifequal x 5 and y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     462            'ifequal-error05': ('{% ifequal x 5 or %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     463            'ifequal-error06': ('{% ifequal x 5 or y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     464            'ifequal-error07': ('{% ifequal x %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     465            'ifequal-error08': ('{% ifequal x or %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     466            'ifequal-error09': ('{% ifequal x and %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     467            'ifequal-error10': ('{% ifequal x or y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     468            'ifequal-error11': ('{% ifequal x and y %}yes{% endifequal %}', {'x': 5, 'y': 10, 'z': 15}, template.TemplateSyntaxError),
     469           
    417470
    418471            ### IFNOTEQUAL TAG ########################################################
    419472            'ifnotequal01': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
    420473            'ifnotequal02': ("{% ifnotequal a b %}yes{% endifnotequal %}", {"a": 1, "b": 1}, ""),
    421474            'ifnotequal03': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 2}, "yes"),
    422475            'ifnotequal04': ("{% ifnotequal a b %}yes{% else %}no{% endifnotequal %}", {"a": 1, "b": 1}, "no"),
    423 
     476           
     477            # AND CLAUSES
     478            'ifnotequal-and01': ("{% ifnotequal a 2 and b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
     479            'ifnotequal-and02': ("{% ifnotequal a 3 and b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
     480            'ifnotequal-and03': ("{% ifnotequal a 2 and b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
     481            'ifnotequal-and04': ("{% ifnotequal a 3 and b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
     482           
     483            # OR CLAUSES
     484            'ifnotequal-or01': ("{% ifnotequal a 2 or b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, ""),
     485            'ifnotequal-or02': ("{% ifnotequal a 3 or b 4 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
     486            'ifnotequal-or03': ("{% ifnotequal a 2 or b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
     487            'ifnotequal-or04': ("{% ifnotequal a 3 or b 5 %}yes{% endifnotequal %}", {"a": 2, "b": 4}, "yes"),
     488           
    424489            ### INCLUDE TAG ###########################################################
    425490            'include01': ('{% include "basic-syntax01" %}', {}, "something cool"),
    426491            'include02': ('{% include "basic-syntax02" %}', {'headline': 'Included'}, "Included"),
  • AUTHORS

     
    147147    Yasushi Masuda <whosaysni@gmail.com>
    148148    mattycakes@gmail.com
    149149    Jason McBrayer <http://www.carcosa.net/jason/>
    150     mccutchen@gmail.com
     150    Will McCutchen <mccutchen@gmail.com>
    151151    michael.mcewan@gmail.com
    152152    mikko@sorl.net
    153153    mitakummaa@gmail.com
  • docs/templates.txt

     
    561561~~~~~~~
    562562
    563563Output the contents of the block if the two arguments equal each other.
     564As in the ``{% if %}`` tag, ``ifequal`` tags do not allow both ``and`` and
     565``or`` clauses in the same tag.
    564566
    565567Example::
    566568
     
    568570        ...
    569571    {% endifequal %}
    570572
     573        {% ifequal user.id comment.user_id or ifequal user.id 0 %}
     574                ...
     575        {% endifequal %}
     576       
    571577As in the ``{% if %}`` tag, an ``{% else %}`` clause is optional.
    572578
    573579The arguments can be hard-coded strings, so the following is valid::
Back to Top