11
11
from django .template import Node , NodeList , Template , Context , Variable
12
12
from django .template import TemplateSyntaxError , VariableDoesNotExist , BLOCK_TAG_START , BLOCK_TAG_END , VARIABLE_TAG_START , VARIABLE_TAG_END , SINGLE_BRACE_START , SINGLE_BRACE_END , COMMENT_TAG_START , COMMENT_TAG_END
13
13
from django .template import get_library , Library , InvalidTemplateLibrary
14
+ from django .template .smartif import IfParser , Literal
14
15
from django .conf import settings
15
16
from django .utils .encoding import smart_str , smart_unicode
16
17
from django .utils .itercompat import groupby
@@ -227,10 +228,9 @@ def render(self, context):
227
228
return self .nodelist_false .render (context )
228
229
229
230
class IfNode (Node ):
230
- def __init__ (self , bool_exprs , nodelist_true , nodelist_false , link_type ):
231
- self .bool_exprs = bool_exprs
231
+ def __init__ (self , var , nodelist_true , nodelist_false = None ):
232
232
self .nodelist_true , self .nodelist_false = nodelist_true , nodelist_false
233
- self .link_type = link_type
233
+ self .var = var
234
234
235
235
def __repr__ (self ):
236
236
return "<If node>"
@@ -250,28 +250,10 @@ def get_nodes_by_type(self, nodetype):
250
250
return nodes
251
251
252
252
def render (self , context ):
253
- if self .link_type == IfNode .LinkTypes .or_ :
254
- for ifnot , bool_expr in self .bool_exprs :
255
- try :
256
- value = bool_expr .resolve (context , True )
257
- except VariableDoesNotExist :
258
- value = None
259
- if (value and not ifnot ) or (ifnot and not value ):
260
- return self .nodelist_true .render (context )
261
- return self .nodelist_false .render (context )
262
- else :
263
- for ifnot , bool_expr in self .bool_exprs :
264
- try :
265
- value = bool_expr .resolve (context , True )
266
- except VariableDoesNotExist :
267
- value = None
268
- if not ((value and not ifnot ) or (ifnot and not value )):
269
- return self .nodelist_false .render (context )
253
+ if self .var .eval (context ):
270
254
return self .nodelist_true .render (context )
271
-
272
- class LinkTypes :
273
- and_ = 0 ,
274
- or_ = 1
255
+ else :
256
+ return self .nodelist_false .render (context )
275
257
276
258
class RegroupNode (Node ):
277
259
def __init__ (self , target , expression , var_name ):
@@ -761,6 +743,27 @@ def ifnotequal(parser, token):
761
743
return do_ifequal (parser , token , True )
762
744
ifnotequal = register .tag (ifnotequal )
763
745
746
+ class TemplateLiteral (Literal ):
747
+ def __init__ (self , value , text ):
748
+ self .value = value
749
+ self .text = text # for better error messages
750
+
751
+ def display (self ):
752
+ return self .text
753
+
754
+ def eval (self , context ):
755
+ return self .value .resolve (context , ignore_failures = True )
756
+
757
+ class TemplateIfParser (IfParser ):
758
+ error_class = TemplateSyntaxError
759
+
760
+ def __init__ (self , parser , * args , ** kwargs ):
761
+ self .template_parser = parser
762
+ return super (TemplateIfParser , self ).__init__ (* args , ** kwargs )
763
+
764
+ def create_var (self , value ):
765
+ return TemplateLiteral (self .template_parser .compile_filter (value ), value )
766
+
764
767
#@register.tag(name="if")
765
768
def do_if (parser , token ):
766
769
"""
@@ -805,55 +808,29 @@ def do_if(parser, token):
805
808
There are some athletes and absolutely no coaches.
806
809
{% endif %}
807
810
808
- ``if`` tags do not allow ``and`` and ``or`` clauses with the same tag,
809
- because the order of logic would be ambigous. For example, this is
810
- invalid::
811
+ Comparison operators are also available, and the use of filters is also
812
+ allowed, for example:
811
813
812
- {% if athlete_list and coach_list or cheerleader_list %}
814
+ {% if articles|length >= 5 %}...{% endif %}
813
815
814
- If you need to combine `` and`` and ``or`` to do advanced logic, just use
815
- nested if tags. For example::
816
+ Arguments and operators _must_ have a space between them, so
817
+ ``{% if 1>2 %}`` is not a valid if tag.
816
818
817
- {% if athlete_list %}
818
- {% if coach_list or cheerleader_list %}
819
- We have athletes, and either coaches or cheerleaders!
820
- {% endif %}
821
- {% endif %}
819
+ All supported operators are: ``or``, ``and``, ``in``, ``==`` (or ``=``),
820
+ ``!=``, ``>``, ``>=``, ``<`` and ``<=``.
821
+
822
+ Operator precedence follows Python.
822
823
"""
823
- bits = token .contents .split ()
824
- del bits [0 ]
825
- if not bits :
826
- raise TemplateSyntaxError ("'if' statement requires at least one argument" )
827
- # Bits now looks something like this: ['a', 'or', 'not', 'b', 'or', 'c.d']
828
- bitstr = ' ' .join (bits )
829
- boolpairs = bitstr .split (' and ' )
830
- boolvars = []
831
- if len (boolpairs ) == 1 :
832
- link_type = IfNode .LinkTypes .or_
833
- boolpairs = bitstr .split (' or ' )
834
- else :
835
- link_type = IfNode .LinkTypes .and_
836
- if ' or ' in bitstr :
837
- raise TemplateSyntaxError , "'if' tags can't mix 'and' and 'or'"
838
- for boolpair in boolpairs :
839
- if ' ' in boolpair :
840
- try :
841
- not_ , boolvar = boolpair .split ()
842
- except ValueError :
843
- raise TemplateSyntaxError , "'if' statement improperly formatted"
844
- if not_ != 'not' :
845
- raise TemplateSyntaxError , "Expected 'not' in if statement"
846
- boolvars .append ((True , parser .compile_filter (boolvar )))
847
- else :
848
- boolvars .append ((False , parser .compile_filter (boolpair )))
824
+ bits = token .split_contents ()[1 :]
825
+ var = TemplateIfParser (parser , bits ).parse ()
849
826
nodelist_true = parser .parse (('else' , 'endif' ))
850
827
token = parser .next_token ()
851
828
if token .contents == 'else' :
852
829
nodelist_false = parser .parse (('endif' ,))
853
830
parser .delete_first_token ()
854
831
else :
855
832
nodelist_false = NodeList ()
856
- return IfNode (boolvars , nodelist_true , nodelist_false , link_type )
833
+ return IfNode (var , nodelist_true , nodelist_false )
857
834
do_if = register .tag ("if" , do_if )
858
835
859
836
#@register.tag
0 commit comments