got a question here.
I have the following
{% if form.tpl.yes_no_required == True %}
<!-- path 1 -->
{% else %}
{% if form.tpl.yes_no_required == False %}
<!-- path 2 -->
{% endif %}
{% endif %}
The value for form.tpl.yes_no_required is None, but I was routed to path 2. Can anyone please explain why is this so? EDIT: if the value is none, i do not want it display anything.
You can't use the template language to test against what you think are constants, the parser is actually testing 2 "literals".
The parser tests for 2 literals with names 'None' and 'False'.
When parser tries to resolve these in the context a VariableDoesNotExist exception is thrown and both objects resolve to the python value None
and None == None.
from django.template import Context, Template
t = Template("{% if None == False %} not what you think {% endif %}")
c = Context({"foo": foo() })
prints u' not what you think '
c = Context({'None':None})
t.render(c)
prints u' not what you think '
c = Context({'None':None, 'False':False})
t.render(c)
prints u''
None != False None != True also ...
do some things like this for none item
{% if form.tpl.yes_no_required %}
<!-- path 1 -->
{% else %}
{% if not form.tpl.yes_no_required %}
<!-- path 2 -->
{% endif %}
{% endif %}
Related
How i can implement this condition in django template with multiple and or statement in if?
{% if ((email_setting.twitter_link is not None and email_setting.twitter_link != '')
or (email_setting.instagram_link is not None and email_setting.instagram_link != '')
or (email_setting.fb_link is not None and email_setting.fb_link!= '') ) %}
Here my body
{% endif %}
this give me an error
TemplateSyntaxError at /settings/emailView
Could not parse the remainder: '((email_setting.twitter_link' from '((email_setting.twitter_link'
You can expresss this as:
{% if email_setting.twitter_link or email_setting.instagram_link or email_setting.fb_link %}
…
{% endif %}
Here we check the truthiness of the twitter_link and other settings. The truthiness of None and the empty string are False whereas for a non-empty string, it is True.
I'm looping through a result set and when a certain condition is met I want to run through a conditional statement. After that condition has been met I want to continue looping through the result set without running through that condition.
Does anyone have any ideas on how I could go about this?
Edit:
Here is what I'm trying to achieve.
{% flag = false %}
{% for row in results %}
{{ row.field }}
{% if row.is_active and !flag %}
<br />
{% flag = true %}
{% endif %}
{% endfor %}
It seems that you want to do one thing with the first part of the QuerySet, and other thing with the rest. Split it in the view.
views.py
def split_list(list, condition):
list1, list2 = [], []
condition_satisfied = False
for element in list:
if not condition_satisfied and condition(element):
condition_satisfied = True
if not condition_satisfied:
list1.append(element)
else:
list2.append(element)
return list1, list2
def your_view(request):
results = YourModel.objects.all()
results1, results2 = split_list(results, condition)
return render(request, 'template.html', {
'results1': results1,
'results2': results2
})
template.html
{% for result in results1 %}
{% if result == whatever %}
<p>Condition satisfied</p>
{% else %}
<p>Condition not satisfied</p>
{% endif %}
{% endfor %}
{% for result in results2 %}
{{ result }}
{% endfor %}
Django doesn't have this feature, and for good reason. Templates should not contain this kind of logic. It should be done within the View.
I am trying to run two tests:
{% if profile.id != 100 or profile.location == NULL %}
however it seems to not work. I couldn't find in the docs why this isn't working. Any ideas?
EDIT:
In the SQL db, the value for profile.location is NULL. The rendered result is None.
EDIT 2:
Here is the full chain. There are 4 ways to grab a user's location. It is a giant mess as you can see...
{% if profile.city.id != 104 or profile.city %}
{{profile.city}}
{% else %}
{% if profile.mylocation != '' %}
{{ profile.mylocation }}
{% else %}
{% if profile.fbconnect == 1 and profile.location != '' and profile.location != "None" %}
{{profile.location}}
{% else %}
{% if profile.sglocation.city %}{{profile.sglocation.city}}{% else %}{{profile.sglocation.country}}{% endif %}
{% endif %}
{% endif %}
{% endif %}
There's no NULL. Try:
{% if profile.id != 100 or not profile.location %}
If I were you, I would throw all that logic back into Python, for example:
class Profile(models.Model):
[your model fields and stuff]
def get_location(self):
[your location logic]
Then in the template you can just do:
{{ profile.get_location }}
How do I check if a variable is False using Django template syntax?
{% if myvar == False %}
Doesn't seem to work.
Note that I very specifically want to check if it has the Python value False. This variable could be an empty array too, which is not what I want to check for.
For posterity, I have a few NullBooleanFields and here's what I do:
To check if it's True:
{% if variable %}True{% endif %}
To check if it's False (note this works because there's only 3 values -- True/False/None):
{% if variable != None %}False{% endif %}
To check if it's None:
{% if variable == None %}None{% endif %}
I'm not sure why, but I can't do variable == False, but I can do variable == None.
Django 1.10 (release notes) added the is and is not comparison operators to the if tag. This change makes identity testing in a template pretty straightforward.
In[2]: from django.template import Context, Template
In[3]: context = Context({"somevar": False, "zero": 0})
In[4]: compare_false = Template("{% if somevar is False %}is false{% endif %}")
In[5]: compare_false.render(context)
Out[5]: u'is false'
In[6]: compare_zero = Template("{% if zero is not False %}not false{% endif %}")
In[7]: compare_zero.render(context)
Out[7]: u'not false'
If You are using an older Django then as of version 1.5 (release notes) the template engine interprets True, False and None as the corresponding Python objects.
In[2]: from django.template import Context, Template
In[3]: context = Context({"is_true": True, "is_false": False,
"is_none": None, "zero": 0})
In[4]: compare_true = Template("{% if is_true == True %}true{% endif %}")
In[5]: compare_true.render(context)
Out[5]: u'true'
In[6]: compare_false = Template("{% if is_false == False %}false{% endif %}")
In[7]: compare_false.render(context)
Out[7]: u'false'
In[8]: compare_none = Template("{% if is_none == None %}none{% endif %}")
In[9]: compare_none.render(context)
Out[9]: u'none'
Although it does not work the way one might expect.
In[10]: compare_zero = Template("{% if zero == False %}0 == False{% endif %}")
In[11]: compare_zero.render(context)
Out[11]: u'0 == False'
I think this will work for you:
{% if not myvar %}
You could write a custom template filter to do this in a half-dozen lines of code:
from django.template import Library
register = Library()
#register.filter
def is_false(arg):
return arg is False
Then in your template:
{% if myvar|is_false %}...{% endif %}
Of course, you could make that template tag much more generic... but this suits your needs specifically ;-)
In old version you can only use the ifequal or ifnotequal
{% ifequal YourVariable ExpectValue %}
# Do something here.
{% endifequal %}
Example:
{% ifequal userid 1 %}
Hello No.1
{% endifequal %}
{% ifnotequal username 'django' %}
You are not django!
{% else %}
Hi django!
{% endifnotequal %}
As in the if tag, an {% else %} clause is optional.
The arguments can be hard-coded strings, so the following is valid:
{% ifequal user.username "adrian" %}
...
{% endifequal %}
An alternative to the ifequal tag is to use the if tag and the == operator.
ifnotequal
Just like ifequal, except it tests that the two arguments are not equal.
An alternative to the ifnotequal tag is to use the if tag and the != operator.
However, now we can use if/else easily
{% if somevar >= 1 %}
{% endif %}
{% if "bc" in "abcdef" %}
This appears since "bc" is a substring of "abcdef"
{% endif %}
Complex expressions
All of the above can be combined to form complex expressions. For such expressions, it can be important to know how the operators are grouped when the expression is evaluated - that is, the precedence rules. The precedence of the operators, from lowest to highest, is as follows:
or
and
not
in
==, !=, <, >, <=, >=
More detail
https://docs.djangoproject.com/en/dev/ref/templates/builtins/
Just ran into this again (certain I had before and came up with a less-than-satisfying solution).
For a tri-state boolean semantic (for example, using models.NullBooleanField), this works well:
{% if test.passed|lower == 'false' %} ... {% endif %}
Or if you prefer getting excited over the whole thing...
{% if test.passed|upper == 'FALSE' %} ... {% endif %}
Either way, this handles the special condition where you don't care about the None (evaluating to False in the if block) or True case.
I have had this issue before, which I solved by nested if statements first checking for none type separately.
{% if object.some_bool == None %}Empty
{% else %}{% if not object.some_bool %}False{% else %}True{% endif %}{% endif %}
If you only want to test if its false, then just
{% if some_bool == None %}{% else %}{% if not some_bool %}False{% endif %}{% endif %}
EDIT: This seems to work.
{% if 0 == a|length %}Zero-length array{% else %}{% if a == None %}None type{% else %}{% if not a %}False type{% else %}True-type {% endif %}{% endif %}{% endif %}
Now zero-length arrays are recognized as such; None types as None types; falses as False; Trues as trues; strings/arrays above length 0 as true.
You could also include in the Context a variable false_list = [False,] and then do
{% if some_bool in false_list %}False {% endif %}
Look at the yesno helper
Eg:
{{ myValue|yesno:"itwasTrue,itWasFalse,itWasNone" }}
I've just come up with the following which is looking good in Django 1.8
Try this instead of value is not False:
if value|stringformat:'r' != 'False'
Try this instead of value is True:
if value|stringformat:'r' == 'True'
unless you've been really messing with repr methods to make value look like a boolean I reckon this should give you a firm enough assurance that value is True or False.
This is far easier to check in Python (i.e. your view code) than in the template, because the Python code is simply:
myvar is False
Illustrating:
>>> False is False
True
>>> None is False
False
>>> [] is False
False
The problem at the template level is that the template if doesn't parse is (though it does parse in). Also, if you don't mind it, you could try to patch support for is into the template engine; base it on the code for ==.
you can use the int value of true and false
True = any int
False = zero
so, if we take an example:
{% if user.is_authenticated == 1 %}
do something
{% endif %}
this mean in python
if user.is_authenticated:
#do something
and
{% if user.is_authenticated == 0 %}
do something
{% endif %}
this mean in python
if not user.is_authenticated :
#do something
OR equal
if !(user.is_authenticated) :
#do something
OR equal
if user.is_authenticated == False :
#do something
It can be done:if you use "select" tag.
{% if service.active == 0 %} selected {% endif%}
I found a link to have a 'switch' tag in Django templates, but I was wondering if this can be somehow achieved without it. Using only the stuff which comes with Django? Basically is there other way then using multiple 'if' or 'ifequal' statements?
Thanks in advance for any tips/suggestions.
As of Django 1.4, there is {% elif %}:
{% if a %}
thing
{% elif b %}
other thing
{% elif c %}
another thing
{% endif %}
To the previous responders: Without understanding the use case, you've made assumptions and criticized the questioner. #Ber says "all over the place" which is certainly not implied by the questioner. Not fair.
I have a case where I would like to do a {% switch %} statement in exactly one place in my Django template. Not only is it not convenient to move the equivalent of the switch statement into Python code, but that would actually make both the view and the template harder to read and take simple conditional logic that belongs in one place and split it into two places.
In many cases where I could imagine a {% switch %} (or an {% if %}) being useful, not using one requires putting HTML in a view. That's a far worse sin and is why {% if %} exists in the first place. {% switch %} is no different.
Fortunately, Django is extensible and multiple people have implemented switch. Check out:
Switch template tag
from django import template
from django.template import Library, Node, VariableDoesNotExist
register = Library()
#register.tag(name="switch")
def do_switch(parser, token):
"""
The ``{% switch %}`` tag compares a variable against one or more values in
``{% case %}`` tags, and outputs the contents of the matching block. An
optional ``{% else %}`` tag sets off the default output if no matches
could be found::
{% switch result_count %}
{% case 0 %}
There are no search results.
{% case 1 %}
There is one search result.
{% else %}
Jackpot! Your search found {{ result_count }} results.
{% endswitch %}
Each ``{% case %}`` tag can take multiple values to compare the variable
against::
{% switch username %}
{% case "Jim" "Bob" "Joe" %}
Me old mate {{ username }}! How ya doin?
{% else %}
Hello {{ username }}
{% endswitch %}
"""
bits = token.contents.split()
tag_name = bits[0]
if len(bits) != 2:
raise template.TemplateSyntaxError("'%s' tag requires one argument" % tag_name)
variable = parser.compile_filter(bits[1])
class BlockTagList(object):
# This is a bit of a hack, as it embeds knowledge of the behaviour
# of Parser.parse() relating to the "parse_until" argument.
def __init__(self, *names):
self.names = set(names)
def __contains__(self, token_contents):
name = token_contents.split()[0]
return name in self.names
# Skip over everything before the first {% case %} tag
parser.parse(BlockTagList('case', 'endswitch'))
cases = []
token = parser.next_token()
got_case = False
got_else = False
while token.contents != 'endswitch':
nodelist = parser.parse(BlockTagList('case', 'else', 'endswitch'))
if got_else:
raise template.TemplateSyntaxError("'else' must be last tag in '%s'." % tag_name)
contents = token.contents.split()
token_name, token_args = contents[0], contents[1:]
if token_name == 'case':
tests = map(parser.compile_filter, token_args)
case = (tests, nodelist)
got_case = True
else:
# The {% else %} tag
case = (None, nodelist)
got_else = True
cases.append(case)
token = parser.next_token()
if not got_case:
raise template.TemplateSyntaxError("'%s' must have at least one 'case'." % tag_name)
return SwitchNode(variable, cases)
class SwitchNode(Node):
def __init__(self, variable, cases):
self.variable = variable
self.cases = cases
def __repr__(self):
return "<Switch node>"
def __iter__(self):
for tests, nodelist in self.cases:
for node in nodelist:
yield node
def get_nodes_by_type(self, nodetype):
nodes = []
if isinstance(self, nodetype):
nodes.append(self)
for tests, nodelist in self.cases:
nodes.extend(nodelist.get_nodes_by_type(nodetype))
return nodes
def render(self, context):
try:
value_missing = False
value = self.variable.resolve(context, True)
except VariableDoesNotExist:
no_value = True
value_missing = None
for tests, nodelist in self.cases:
if tests is None:
return nodelist.render(context)
elif not value_missing:
for test in tests:
test_value = test.resolve(context, True)
if value == test_value:
return nodelist.render(context)
else:
return ""
Unfortunately, this is not possible with the default Django template engine. You'll have to write something ugly like this to emulate a switch.
{% if a %}
{{ a }}
{% else %}
{% if b %}
{{ b }}
{% else %}
{% if c %}
{{ c }}
{% else %}
{{ default }}
{% endif %}
{% endif %}
{% endif %}
or if only one if condition can be true and you don't need a default.
{% if a %}
{{ a }}
{% endif %}
{% if b %}
{{ b }}
{% endif %}
{% if c %}
{{ c }}
{% endif %}
Usually, when the template engine is not powerful enough to accomplish what you want this is a sign that the code should be moved into Django view instead of in the template. For example:
# Django view
if a:
val = a
elif b:
val = b
elif c:
val = c
else:
val = default
# Template
{{ val }}
In a very general view, the need for a switch statement is a sign that there is a need to create new classes and objects that capture the different "cases".
Then, instead of "swtich"ing all over the place, you only need to call an object method or reference an object attribute and your done.