Created
February 11, 2015 06:53
-
-
Save zii/95363a1297ad745fe56d to your computer and use it in GitHub Desktop.
add elif to old django
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#coding: utf-8 | |
"""Default tags used by the template system, available to all templates.""" | |
from __future__ import unicode_literals | |
from django.template import (Node, NodeList, Library, TextNode, | |
TemplateSyntaxError, VariableDoesNotExist) | |
from django.template.smartif import IfParser, Literal | |
register = Library() | |
class IfNode(Node): | |
def __init__(self, conditions_nodelists): | |
self.conditions_nodelists = conditions_nodelists | |
def __repr__(self): | |
return "<IfNode>" | |
def __iter__(self): | |
for _, nodelist in self.conditions_nodelists: | |
for node in nodelist: | |
yield node | |
@property | |
def nodelist(self): | |
return NodeList(node for _, nodelist in self.conditions_nodelists for node in nodelist) | |
def render(self, context): | |
for condition, nodelist in self.conditions_nodelists: | |
if condition is not None: # if / elif clause | |
try: | |
match = condition.eval(context) | |
except VariableDoesNotExist: | |
match = None | |
else: # else clause | |
match = True | |
if match: | |
return nodelist.render(context) | |
return '' | |
class TemplateLiteral(Literal): | |
def __init__(self, value, text): | |
self.value = value | |
self.text = text # for better error messages | |
def display(self): | |
return self.text | |
def eval(self, context): | |
return self.value.resolve(context, ignore_failures=True) | |
class TemplateIfParser(IfParser): | |
error_class = TemplateSyntaxError | |
def __init__(self, parser, *args, **kwargs): | |
self.template_parser = parser | |
super(TemplateIfParser, self).__init__(*args, **kwargs) | |
def create_var(self, value): | |
return TemplateLiteral(self.template_parser.compile_filter(value), value) | |
def v17_parse(self, parse_until=[]): | |
"Pick out from v1.7's Parser.parse" | |
nodelist = self.create_nodelist() | |
while self.tokens: | |
token = self.next_token() | |
# Use the raw values here for TOKEN_* for a tiny performance boost. | |
if token.token_type == 0: # TOKEN_TEXT | |
self.extend_nodelist(nodelist, TextNode(token.contents), token) | |
elif token.token_type == 1: # TOKEN_VAR | |
if not token.contents: | |
self.empty_variable(token) | |
filter_expression = self.compile_filter(token.contents) | |
var_node = self.create_variable_node(filter_expression) | |
self.extend_nodelist(nodelist, var_node,token) | |
elif token.token_type == 2: # TOKEN_BLOCK | |
try: | |
command = token.contents.split()[0] | |
except IndexError: | |
self.empty_block_tag(token) | |
if command in parse_until: | |
# put token back on token list so calling | |
# code knows why it terminated | |
self.prepend_token(token) | |
return nodelist | |
# execute callback function for this tag and append | |
# resulting node | |
self.enter_command(command, token) | |
try: | |
compile_func = self.tags[command] | |
except KeyError: | |
self.invalid_block_tag(token, command, parse_until) | |
try: | |
compiled_result = compile_func(self, token) | |
except TemplateSyntaxError as e: | |
if not self.compile_function_error(token, e): | |
raise | |
self.extend_nodelist(nodelist, compiled_result, token) | |
self.exit_command() | |
if parse_until: | |
self.unclosed_block_tag(parse_until) | |
return nodelist | |
def do_if(parser, token): | |
""" | |
The ``{% if %}`` tag evaluates a variable, and if that variable is "true" | |
(i.e., exists, is not empty, and is not a false boolean value), the | |
contents of the block are output: | |
:: | |
{% if athlete_list %} | |
Number of athletes: {{ athlete_list|count }} | |
{% elif athlete_in_locker_room_list %} | |
Athletes should be out of the locker room soon! | |
{% else %} | |
No athletes. | |
{% endif %} | |
In the above, if ``athlete_list`` is not empty, the number of athletes will | |
be displayed by the ``{{ athlete_list|count }}`` variable. | |
As you can see, the ``if`` tag may take one or several `` {% elif %}`` | |
clauses, as well as an ``{% else %}`` clause that will be displayed if all | |
previous conditions fail. These clauses are optional. | |
``if`` tags may use ``or``, ``and`` or ``not`` to test a number of | |
variables or to negate a given variable:: | |
{% if not athlete_list %} | |
There are no athletes. | |
{% endif %} | |
{% if athlete_list or coach_list %} | |
There are some athletes or some coaches. | |
{% endif %} | |
{% if athlete_list and coach_list %} | |
Both athletes and coaches are available. | |
{% endif %} | |
{% if not athlete_list or coach_list %} | |
There are no athletes, or there are some coaches. | |
{% endif %} | |
{% if athlete_list and not coach_list %} | |
There are some athletes and absolutely no coaches. | |
{% endif %} | |
Comparison operators are also available, and the use of filters is also | |
allowed, for example:: | |
{% if articles|length >= 5 %}...{% endif %} | |
Arguments and operators _must_ have a space between them, so | |
``{% if 1>2 %}`` is not a valid if tag. | |
All supported operators are: ``or``, ``and``, ``in``, ``not in`` | |
``==`` (or ``=``), ``!=``, ``>``, ``>=``, ``<`` and ``<=``. | |
Operator precedence follows Python. | |
""" | |
# {% if ... %} | |
bits = token.split_contents()[1:] | |
condition = TemplateIfParser(parser, bits).parse() | |
nodelist = v17_parse(parser, ('elif', 'else', 'endif')) | |
conditions_nodelists = [(condition, nodelist)] | |
token = parser.next_token() | |
# {% elif ... %} (repeatable) | |
while token.contents.startswith('elif'): | |
bits = token.split_contents()[1:] | |
condition = TemplateIfParser(parser, bits).parse() | |
nodelist = v17_parse(parser, ('elif', 'else', 'endif')) | |
conditions_nodelists.append((condition, nodelist)) | |
token = parser.next_token() | |
# {% else %} (optional) | |
if token.contents == 'else': | |
nodelist = parser.parse(('endif',)) | |
conditions_nodelists.append((None, nodelist)) | |
token = parser.next_token() | |
# {% endif %} | |
assert token.contents == 'endif' | |
return IfNode(conditions_nodelists) | |
register.tag("if", do_if) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment