Niedawno stanął przed samą zagadką, a po spojrzeniu w sposób tag {% if %}
jest zorganizowany oto co wymyśliłem:
from django.template.base import VariableDoesNotExist
from django.template.defaulttags import IfNode
from django.template.smartif import IfParser, Literal
# Used as a value for ifdef and ifndef tags
undefined = object()
class IfDefLiteral(Literal):
def eval(self, context):
if not self.value in context:
# Can't raise an exception here because Operator catches it
return undefined
class IfDefParser(IfParser):
def create_var(self, value):
return IfDefLiteral(value)
class IfDefNode(IfNode):
def __init__(self, defined=True, *args, **kwargs):
self.defined = defined
super(IfDefNode, self).__init__(*args, **kwargs)
def __repr__(self):
return "<%s>" % self.__class__.__name__
def render(self, context):
for condition, nodelist in self.conditions_nodelists:
match = undefined
if condition is not None: # if/elif clause
try:
match = condition.eval(context)
except VariableDoesNotExist:
pass
if condition is None or ( # else clause, always render
(self.defined and match is not undefined) or
(match is undefined and not self.defined)):
return nodelist.render(context)
return ''
def _gen_ifdef(parser, token, block_tokens, defined):
# {% if ... %}
bits = token.split_contents()[1:]
condition = IfDefParser(bits).parse()
nodelist = parser.parse(block_tokens)
conditions_nodelists = [(condition, nodelist)]
token = parser.next_token()
# {% elif ... %} (repeatable)
while token.contents.startswith(block_tokens[0]):
bits = token.split_contents()[1:]
condition = IfDefParser(bits).parse()
nodelist = parser.parse(block_tokens)
conditions_nodelists.append((condition, nodelist))
token = parser.next_token()
# {% else %} (optional)
if token.contents == 'else':
nodelist = parser.parse(block_tokens[-1:])
conditions_nodelists.append((None, nodelist))
token = parser.next_token()
# {% endif %}
assert token.contents == block_tokens[-1]
return IfDefNode(defined, conditions_nodelists)
@register.tag
def ifdef(parser, token):
"""Check if variable is defined in the context
Unlike the {% if %} tag, this renders the block if the variable(s)
exist within the context, not only if they are truthy. That is, variables
with None, 0 or [] values would also render the block.
"""
return _gen_ifdef(parser, token, ('elifdef', 'else', 'endifdef'), True)
@register.tag
def ifndef(parser, token):
"""Check if variable is *not* defined in the context
This is the opposite of {% ifdef %}.
"""
return _gen_ifdef(parser, token, ('elifndef', 'else', 'endifndef'), False)
Wtedy go używać jak {% if %}
tag w szablonie:
{% ifdef letters or numbers %}
{# do something with letters or numbers #}
{% else %}
{# variables are not defined here #}
{% endifdef %}
Nie jestem pewien, czy jest prostszy sposób, aby to osiągnąć, i chociaż nie jestem zbyt zadowolony z podejścia, wydaje się, że działa dobrze w moim przypadku użycia. Mam nadzieję że to pomoże!
dziękuję! Sądzę, że to najczystsze z wielu nieczystych rozwiązań. – sha