2013-06-11 7 views
5

Ich schreibe eine Django Vorlage und ich möchte zwischen der Existenz einer Kontextvariablen vs es keine, leer etc. Ich habe meine Hausaufgaben gemacht und es scheint überraschend schwer. Insbesondere ist es das, was ichdjango check Existenz der Vorlage Kontextvariable

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> 

Mit der {% if %} dicey ist, weil es zu tun, ich versucht, fehlschlägt, wenn letters doesnt existieren oder die Liste leer ist. Ich möchte letters verwenden, auch wenn sie leer ist (aber im Kontext definiert)

Ich habe das gleiche Problem mit den eingebauten Filtern default und default_if_none Wie kann ich die Existenz einer Kontextvariablen unterscheiden von ihm eine andere Bedeutung Dinge wie None oder Empty

Antwort

4

ich konfrontiert kürzlich die gleichen Rätsel, und nach dem {% if %}-Tag in den Weg suchen, hier ist strukturiert ist, was ich kam mit:

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) 

Dann würden Sie es wie ein {% if %} Tag in Ihrer Vorlage verwenden:

{% ifdef letters or numbers %} 
    {# do something with letters or numbers #} 
{% else %} 
    {# variables are not defined here #} 
{% endifdef %} 

Ich bin mir nicht sicher, ob es einen einfacheren Weg gibt, dies zu erreichen, und obwohl ich mit dem Ansatz nicht allzu glücklich bin, scheint es in meinem Anwendungsfall gut zu funktionieren. Hoffe das hilft!

+0

danke! Ich denke, das ist die sauberste von vielen unsauberen Lösungen. – sha

0

Ich bin nicht sicher, ob diese Art von Logik in Vorlagen verwendet werden sollte, sollten sie einfach sein. So wie ich das lösen würde es einfach hinzufügen (Innenansicht, bevor „if“):

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

jetzt, wenn some_condition = False, als „für“ Schleife nicht in Vorlage ausgeführt, so dass Sie nicht brauchen, "Wenn" dort mehr.