2013-06-11 12 views
5

Sto scrivendo un modello di django e voglio distinguere tra l'esistenza di una variabile di contesto in quanto è Nessuno, vuoto ecc. Ho fatto i miei compiti e sembra sorprendentemente difficile. In particolare, questo è quello che sto cercando di faredjango verifica esistenza della variabile di contesto modello

view 1: 
... 
if some_condition = True: 
    context['letters'] = ['a', 'b', 'c'] # The list might also be empty or None in some cases 
else 
    context['numbers'] = [1, 2, 3] #This list might be empty or None in some cases 

Template 
... 
<ul> 
{% if letters %} 
    {% for x in letter %} 
     <li>{{x}}</li> 
    {%endfor%} 
{% else %} 
    {%for x in numbers%} 
     <li>{{x}}</li> 
    {%endfor%} 
</ul> 

utilizzando il {% if %} è rischiosa, perché è non riesce se letters doesnt esiste o l'elenco è vuoto. Voglio usare letters anche se è vuoto (ma definito nel contesto)

Ho lo stesso problema con i filtri incorporati default e default_if_none Come posso differenziare l'esistenza di una variabile di contesto da esso che è altra cose come Nessuna o Vuoto

risposta

4

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!

+0

grazie! Immagino che questo sia il più pulito di molte soluzioni sporche. – sha

0

Non sono sicuro che questo tipo di logica debba essere utilizzato nei modelli, si suppone che siano semplici. Il modo in cui vorrei risolverlo è sufficiente aggiungere (vista interna, prima di "se"):

context['letters'] = False #([]/None/False) 
if some_condition = True: 
    ... 

ora se some_condition = False, che "per" ciclo non verrà eseguito nel modello, in modo che non è necessario "se" c'è più.

Problemi correlati