recente ho affrontato lo stesso dilemma, e dopo aver guardato nel modo in cui il tag {% if %}
è strutturato ecco cosa mi si avvicinò con:
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)
allora si dovrebbe usarlo come un {% if %}
tag nel modello:
Non sono sicuro che ci sia un modo più semplice per farlo, e anche se non sono molto contento dell'approccio, sembra che funzioni bene nel mio caso d'uso. Spero che questo ti aiuti!
grazie! Immagino che questo sia il più pulito di molte soluzioni sporche. – sha