if condition in django template "{{ }}" - django

Before showing a text I have to evaluate it.
Instead of
{% if value %} text_true {% else %} text_false {% endif %}
Are there anything like:
{{ text_true if value else text_false }}

For the example in your question, you can use the yesno filter
{{ value|yesno:'text_true,text_false' }}

Not with this exact syntax, but there are the default and default_if_none template filters. Those may be what you're looking for.
https://docs.djangoproject.com/en/1.11/ref/templates/builtins/#default

Related

Showing random objects in Django template

In my Django template as I am iterating through a list of objects, I'd like to have one list item say:
<li>Blah</li>
and then another do:
<li>Blah</li>
I see value|random as an option but for some reason this doesn't work:
{% ifequal [1, 2]|random 1 %}
{{ post.title }}
{% else %}
{{ post.title }}
{% endifequal %}
Doing this throws this error:
u'ifequal' takes two arguments
Is there any way to accomplish this? I would think it should be simple but I realize the Django templating language doesn't allow for variable assignments.
Thanks!
You can't put a list directly into the template like that, make_list is what you're after.
make_list returns a list of strings, so this would work.
{% if 12|make_list|random == '1' %}
<li>Blah</li>
{% else %}
<li>Blah</li>
{% endif %}

Django: How to get selected text of DropDown in Template?

In the template I get the whole DropDown correctly shown with something like this:
{{form.deal_type}}
But what if I wanted just the text of the selected dropdown shown?
This shows me just a foreignkey.
{{form.deal_type.value}}
I don't know why you want to do this exactly, but try this.
TO LOOP:
{% for value, text in form.deal_type.field.choices %}
{{ value }}: {{ text }}
{% if value == form.deal_type.value %}
<strong>{{ text }}</strong> <!-- THIS IS THE SELECTED ONE... -->
{% endif %}
{% endfor %}
EDIT:
I meant the above code as an illustration, not that you should use it verbatim. This code will do more like what you want.
{{ form.deal_type.label_tag }}
{% for value, text in form.deal_type.field.choices %}
{% if value == form.deal_type.value %}
{{ text }}
<input type="hidden" name="deal_type" value="{{ value }}" />
{% endif %}
{% endfor %}
I had a similar issue. To solve it I just passed the value to the template directly from the view. So in your view you presumably have something in the way of
data = {'form' :form,}
return render_to_response('destination.html', data, context_instance = RequestContext)
In data you are passing the form that includes deal_type. Add to
data a variable deal_type set equal to Object.deal_type.display_value with
data = {'form' :form,}
if Object.deal_type: data['deal_type'] = Object.deal_type.display_value
return render_to_response('destination.html', data, context_instance = RequestContext)
Then on your template you can just use
{% if condition_to_show_just_text %}
{{deal_type}} {{form.deal_type.as_hidden}}
{% else %}
{{form.deal_type}}
{% endif %}
It may be insiginificant in this case, but it seemed to me that if the list was long, iterating with the for loop on the template would be less efficient than pulling directly from the object

Django template for loop. Member before

I want to create such loop:
{% for object in objects %}
{% if object.before != object %}
{{ object }} this is different
{% else %}
{{ object }} this is the same
{% endfor %}
Based on https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#for I can't. Is there really no simple way to do this? Or I just need to use counter and check for objects[counter-1]?
P.S. .before is theoretical and objects is simple query list. I want to take and do something with the loop member that encountered before current loop member.
Check ifchanged template tag
There is a "simple way" to do this: write a custom template tag. They're really not hard. This would probably do the trick (untested):
#register.simple_tag
def compare_objects(object_list):
comparisons = []
for i in range(1, len(object_list)):
if object_list[i] > object_list[i-1]:
comparisons.append('bigger')
else:
comparisons.append('smaller')
return comparisons
The built-in template tags and filters don't make it easy (as of Django 1.4), but it is possible by using the with tag to cache variables and the add, slugify, and slice filters to generate a new list with only one member.
The following example creates a new list whose sole member is the previous member of the forloop:
{% for item in list %}
{% if not forloop.first %}
{% with forloop.counter0|add:"-1" as previous %}
{% with previous|slugify|add:":"|add:previous as subset %}
{% with list|slice:subset as sublist %}
<p>Current item: {{ item }}</p>
<p>Previous item: {{ sublist.0 }}</p>
{% endwith %}
{% endwith %}
{% endwith %}
{% endif %}
{% endfor %}
This isn't an elegant solution, but the django template system has two faults that make this hack unavoidable for those who don't what to write custom tags:
Django template syntax does not allow nested curly parenthesis. Otherwise, we could do this:
{{ list.{{ forloop.counter|add:-1 }} }}
The lookup operator does not accept values stored using with (and perhaps for good reason)
{% with forloop.counter|add:-1 as index %}
{{ list.index }}
{% endwith %}
This code should work just fine as a django template, as long as object has a property or no-argument method called before, and objects is iterable (and '<' is defined).
{% for object in objects %}
{% if object.before < object %}
this is bigger
{% else %}
this is smaller
{% endfor %}

Django Many to Many in template

This is my template tag in a forloop
{{ product.feature_set.all.1.value }}
i want to change the number 1 to the forloop.counter. is this posible?
like:
{{
product.feature_set.all.forloop.counter.value
}}
It does not work like that, but is there a way to do this?
This doesn't make sense. You should be looping through the queryset itself.
{% for feature in product.feature_set.all %}
{{ feature }}
{% endfor %}
Since #Daniel's answer doesn't satisfy you, I thought you might want to try writing a custom filter. Here is a rough draft:
#register.filter
def custom_m2m(queryset, forloop_counter):
return queryset[forloop_counter].value
You can use it in your template like this:
{% for ... %}
{{ product.feature_set.all|custom_m2m:forloop.counter }}
{% endfor %}

How can I change the way a boolean prints in a django template?

I have some django code that prints a BooleanField
it is rendered as True or False, can I change the label to be Agree/Disagree or do I need to write logic for that in the template?
{{ bool_var|yesno:"Agree,Disagree" }}
You can also provide an additional string for the None case. See the docs for yesno for details.
Just another way if you want to have more options like adding HTML elements and classes
{% if var == True %} Yes {% else %} No {% endif %}
You can change Yes and No to any html element; an image or span element
Any of the following may be tried with consistent results:
A.
{% if form.my_bool.value %}
{{ "Yes" }}
{% else %}
{{ "No" }}
{% endif %}
B.
{{ form.my_bool.value|yesno }}
C.
{{ form.my_bool.value|yesno:"Yes,No" }}
D.
{% if form.my_bool.value == True %} Yes {% else %} No {% endif %}
Or simply,
{{ form.my_bool.value }} # Here the output will be True or False, as the case may be.
If your models have been defined as
class mymodel(models.Model):
choices=((True, 'Agree'), (False,'Disagree'),(None,"Maybe"))
attr = models.BooleanField(choices=choices, blank=False, null=True)
You can use the built-in method to retrieve the "pretty" string associated with the value by in your template with
{{ object.get_attr_display }}