Django

Code

Changeset 3108

Show
Ignore:
Timestamp:
06/07/06 22:33:21 (3 years ago)
Author:
adrian
Message:

Fixed #2026 -- Added support for 'and' in template 'if' tags, added dozens of unit tests and updated docs. Thanks, ckknight

Files:

Legend:

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

    r2809 r3108  
    150150 
    151151class IfNode(Node): 
    152     def __init__(self, bool_exprs, nodelist_true, nodelist_false): 
     152    def __init__(self, bool_exprs, nodelist_true, nodelist_false, link_type): 
    153153        self.bool_exprs = bool_exprs 
    154154        self.nodelist_true, self.nodelist_false = nodelist_true, nodelist_false 
     155        self.link_type = link_type 
    155156 
    156157    def __repr__(self): 
     
    172173 
    173174    def render(self, context): 
    174         for ifnot, bool_expr in self.bool_exprs: 
    175             try: 
    176                 value = bool_expr.resolve(context) 
    177             except VariableDoesNotExist: 
    178                 value = None 
    179             if (value and not ifnot) or (ifnot and not value): 
    180                 return self.nodelist_true.render(context) 
    181         return self.nodelist_false.render(context) 
     175        if self.link_type == IfNode.LinkTypes.or_: 
     176            for ifnot, bool_expr in self.bool_exprs: 
     177                try: 
     178                    value = bool_expr.resolve(context) 
     179                except VariableDoesNotExist: 
     180                    value = None 
     181                if (value and not ifnot) or (ifnot and not value): 
     182                    return self.nodelist_true.render(context) 
     183            return self.nodelist_false.render(context) 
     184        else: 
     185            for ifnot, bool_expr in self.bool_exprs: 
     186                try: 
     187                    value = bool_expr.resolve(context) 
     188                except VariableDoesNotExist: 
     189                    value = None 
     190                if not ((value and not ifnot) or (ifnot and not value)): 
     191                    return self.nodelist_false.render(context) 
     192            return self.nodelist_true.render(context) 
     193 
     194    class LinkTypes: 
     195        and_ = 0, 
     196        or_ = 1 
    182197 
    183198class RegroupNode(Node): 
     
    562577        raise TemplateSyntaxError, "'if' statement requires at least one argument" 
    563578    # bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d'] 
    564     boolpairs = ' '.join(bits).split(' or ') 
     579    bitstr = ' '.join(bits) 
     580    boolpairs = bitstr.split(' and ') 
    565581    boolvars = [] 
     582    if len(boolpairs) == 1: 
     583        link_type = IfNode.LinkTypes.or_ 
     584        boolpairs = bitstr.split(' or ') 
     585    else: 
     586        link_type = IfNode.LinkTypes.and_ 
     587        if ' or ' in bitstr: 
     588            raise TemplateSyntaxError, "'if' tags can't mix 'and' and 'or'" 
    566589    for boolpair in boolpairs: 
    567590        if ' ' in boolpair: 
    568             not_, boolvar = boolpair.split() 
     591            try: 
     592                not_, boolvar = boolpair.split() 
     593            except ValueError: 
     594                raise TemplateSyntaxError, "'if' statement improperly formatted" 
    569595            if not_ != 'not': 
    570596                raise TemplateSyntaxError, "Expected 'not' in if statement" 
     
    579605    else: 
    580606        nodelist_false = NodeList() 
    581     return IfNode(boolvars, nodelist_true, nodelist_false
     607    return IfNode(boolvars, nodelist_true, nodelist_false, link_type
    582608do_if = register.tag("if", do_if) 
    583609 
  • django/trunk/docs/templates.txt

    r3076 r3108  
    455455will be displayed if the test fails. 
    456456 
    457 ``if`` tags may use ``or`` or ``not`` to test a number of variables or to negate 
    458 a given variable:: 
     457``if`` tags may use ``and``, ``or`` or ``not`` to test a number of variables or 
     458to negate a given variable:: 
     459 
     460    {% if athlete_list and coach_list %} 
     461        Both athletes and coaches are available. 
     462    {% endif %} 
    459463 
    460464    {% if not athlete_list %} 
     
    469473        There are no athletes or there are some coaches (OK, so 
    470474        writing English translations of boolean logic sounds 
    471         stupid; it's not my fault). 
     475        stupid; it's not our fault). 
    472476    {% endif %} 
    473477 
    474 For simplicity, ``if`` tags do not allow ``and`` clauses; use nested ``if`` 
    475 tags instead:: 
     478    {% if athlete_list and not coach_list %} 
     479        There are some athletes and absolutely no coaches. 
     480    {% endif %} 
     481 
     482``if`` tags don't allow ``and`` and ``or`` clauses within the same tag, because 
     483the order of logic would be ambiguous. For example, this is invalid:: 
     484 
     485    {% if athlete_list and coach_list or cheerleader_list %} 
     486 
     487If you need to combine ``and`` and ``or`` to do advanced logic, just use nested 
     488``if`` tags. For example:: 
    476489 
    477490    {% if athlete_list %} 
    478         {% if coach_list %} 
    479             Number of athletes: {{ athlete_list|length }}. 
    480             Number of coaches: {{ coach_list|length }}. 
     491        {% if coach_list or cheerleader_list %} 
     492            We have athletes, and either coaches or cheerleaders! 
    481493        {% endif %} 
    482494    {% endif %} 
  • django/trunk/tests/othertests/templates.py

    r2927 r3108  
    194194 
    195195    ### FILTER TAG ############################################################ 
    196     #'filterXX': ('', {}, ''), 
    197196    'filter01': ('{% filter upper %}{% endfilter %}', {}, ''), 
    198197    'filter02': ('{% filter upper %}django{% endfilter %}', {}, 'DJANGO'), 
     
    200199 
    201200    ### FIRSTOF TAG ########################################################### 
    202     #'firstofXX': ('', {}, ''), 
    203201    'firstof01': ('{% firstof a b c %}', {'a':0,'b':0,'c':0}, ''), 
    204202    'firstof02': ('{% firstof a b c %}', {'a':1,'b':0,'c':0}, '1'), 
     
    221219    'if-tag03': ("{% if foo %}yes{% else %}no{% endif %}", {}, "no"), 
    222220 
     221    # AND 
     222    'if-tag-and01': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), 
     223    'if-tag-and02': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), 
     224    'if-tag-and03': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), 
     225    'if-tag-and04': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), 
     226    'if-tag-and05': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'), 
     227    'if-tag-and06': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'), 
     228    'if-tag-and07': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'foo': True}, 'no'), 
     229    'if-tag-and08': ("{% if foo and bar %}yes{% else %}no{% endif %}", {'bar': True}, 'no'), 
     230 
     231    # OR 
     232    'if-tag-or01': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), 
     233    'if-tag-or02': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), 
     234    'if-tag-or03': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), 
     235    'if-tag-or04': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), 
     236    'if-tag-or05': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': False}, 'no'), 
     237    'if-tag-or06': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': False}, 'no'), 
     238    'if-tag-or07': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'foo': True}, 'yes'), 
     239    'if-tag-or08': ("{% if foo or bar %}yes{% else %}no{% endif %}", {'bar': True}, 'yes'), 
     240 
     241    # TODO: multiple ORs 
     242 
     243    # NOT 
     244    'if-tag-not01': ("{% if not foo %}no{% else %}yes{% endif %}", {'foo': True}, 'yes'), 
     245    'if-tag-not02': ("{% if not %}yes{% else %}no{% endif %}", {'foo': True}, 'no'), 
     246    'if-tag-not03': ("{% if not %}yes{% else %}no{% endif %}", {'not': True}, 'yes'), 
     247    'if-tag-not04': ("{% if not not %}no{% else %}yes{% endif %}", {'not': True}, 'yes'), 
     248    'if-tag-not05': ("{% if not not %}no{% else %}yes{% endif %}", {}, 'no'), 
     249 
     250    'if-tag-not06': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {}, 'no'), 
     251    'if-tag-not07': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), 
     252    'if-tag-not08': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), 
     253    'if-tag-not09': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), 
     254    'if-tag-not10': ("{% if foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), 
     255 
     256    'if-tag-not11': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {}, 'no'), 
     257    'if-tag-not12': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), 
     258    'if-tag-not13': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), 
     259    'if-tag-not14': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), 
     260    'if-tag-not15': ("{% if not foo and bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'no'), 
     261 
     262    'if-tag-not16': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'), 
     263    'if-tag-not17': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), 
     264    'if-tag-not18': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), 
     265    'if-tag-not19': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), 
     266    'if-tag-not20': ("{% if foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), 
     267 
     268    'if-tag-not21': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {}, 'yes'), 
     269    'if-tag-not22': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'yes'), 
     270    'if-tag-not23': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), 
     271    'if-tag-not24': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), 
     272    'if-tag-not25': ("{% if not foo or bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), 
     273 
     274    'if-tag-not26': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {}, 'yes'), 
     275    'if-tag-not27': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), 
     276    'if-tag-not28': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'no'), 
     277    'if-tag-not29': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'no'), 
     278    'if-tag-not30': ("{% if not foo and not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), 
     279 
     280    'if-tag-not31': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {}, 'yes'), 
     281    'if-tag-not32': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': True}, 'no'), 
     282    'if-tag-not33': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': True, 'bar': False}, 'yes'), 
     283    'if-tag-not34': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': True}, 'yes'), 
     284    'if-tag-not35': ("{% if not foo or not bar %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, 'yes'), 
     285 
     286    # AND and OR raises a TemplateSyntaxError 
     287    'if-tag-error01': ("{% if foo or bar and baz %}yes{% else %}no{% endif %}", {'foo': False, 'bar': False}, template.TemplateSyntaxError), 
     288    'if-tag-error02': ("{% if foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), 
     289    'if-tag-error03': ("{% if foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), 
     290    'if-tag-error04': ("{% if not foo and %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), 
     291    'if-tag-error05': ("{% if not foo or %}yes{% else %}no{% endif %}", {'foo': True}, template.TemplateSyntaxError), 
     292 
    223293    ### IFCHANGED TAG ######################################################### 
    224     #'ifchangedXX': ('', {}, ''), 
    225294    'ifchanged01': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,2,3) }, '123'), 
    226295    'ifchanged02': ('{% for n in num %}{% ifchanged %}{{ n }}{% endifchanged %}{% endfor %}', { 'num': (1,1,3) }, '13'), 
     
    389458 
    390459    ### REGROUP TAG ########################################################### 
    391     #'regroupXX': ('', {}, ''), 
    392460    'regroup01': ('{% regroup data by bar as grouped %}' + \ 
    393461                  '{% for group in grouped %}' + \ 
     
    415483 
    416484    ### TEMPLATETAG TAG ####################################################### 
    417     #'templatetagXX': ('', {}, ''), 
    418485    'templatetag01': ('{% templatetag openblock %}', {}, '{%'), 
    419486    'templatetag02': ('{% templatetag closeblock %}', {}, '%}'), 
     
    424491 
    425492    ### WIDTHRATIO TAG ######################################################## 
    426     #'widthratioXX': ('', {}, ''), 
    427493    'widthratio01': ('{% widthratio a b 0 %}', {'a':50,'b':100}, '0'), 
    428494    'widthratio02': ('{% widthratio a b 100 %}', {'a':0,'b':0}, ''), 
     
    441507    'widthratio09': ('{% widthratio a b %}', {'a':50,'b':100}, template.TemplateSyntaxError), 
    442508    'widthratio10': ('{% widthratio a b 100.0 %}', {'a':50,'b':100}, template.TemplateSyntaxError), 
    443      
     509 
    444510    ### NOW TAG ######################################################## 
    445511    # Simple case 
    446512    'now01' : ('{% now "j n Y"%}', {}, str(datetime.now().day) + ' ' + str(datetime.now().month) + ' ' + str(datetime.now().year)), 
    447      
     513 
    448514    # Check parsing of escaped and special characters 
    449515    'now02' : ('{% now "j "n" Y"%}', {}, template.TemplateSyntaxError),