How to have variable defaults in templates? - python

I want to pass variable defaults to my templates in case of the actual variable is None.
Here is what I mean:
{{ value|default:"Default" }} ## General case.
How can I replace "Default" with my custom variable ?
Is it possible to replace it with another variable ?
Something like :
{{ value|default:{{value2}} }} ## OR Something similar

You can just put another variable instead of constant string like this:
{{ value|default:backup_var }}
I've just tested this, it works fine. Here is my template piece:
<i>{{ my_var|default:user.username}}</i>
I have no my_var defined, so it evaluates to:
<i>admin</i>
Summing up, django parser accepts not only constant values, but also variables as parameters to filters also. But not expressions (I couldn't figure out how to make my expression parsed. But if you need it, you may alsways use {% with var=expr %} ... {% endwith %} for complex situations)

Related

Django template execute on only first occurance of match in a for loop

I have a video table with Foreign Keys that point to a document (multiple videos to one doc). I would like to check every element of that list, and on the first match with a query, enable an element (button that leads elsewhere). My attempts have been to use a for loop and then an if statement such that:
{% for vid in doc.video_set.all %}
{% if vid.query_data == 'match_term' %}
<-- button/link stuff -->
{% initialize variable %}
{% endif %}
{% endfor %}
the idea being if I initialized a variable I could add if "and variable is None" to the if statement and prevent future displays. However, after trying to use "set" and "with" to intialize variables I have been greeted with little more than error messages that seem to indicate these methods dont exist. How would I effectively achieve this functionality.
Django template language does not allow you to set variables like this. Your question is a bit confusing because you are trying to show how you would implement it in the Django template, rather than showing what you want the template to display. Here's a couple of suggestions:
If match_term is constant, you could add a method to your model.
class Doc(models.Model):
def first_match(self):
return self.video_set.filter(query_data='match_term').first()
Then use {{ doc.first_match }} in the template.
If match_term changes, then you might have to write a custom template tag.

Django Templates: How best can the output of executing python code in a Django template be suppressed?

Someone has probably encountered this before, and perhaps even the docs provide a solution already, but I couldn't find it yet. My situation is this:
Just to illustrate the REAL PROBLEM: Assuming I have a list that I pass to the template, and which list I iterate over, with a {% for... in one instance, and in the other, I only need to display its first 5 elements only (based on some condition for example, and not just the first 5 elements of the list). Both loops are being used to output a table dynamically. Now, it's the second instance that's tricky... I adopted the solution here, which utilizes a special Counter Class, passed to the template context, and on which one must invoke the Counter.increment method, to be able to increment the counter - which I then use in my conditional statement, to halt execution of the loop.
The challenge:
I currently have code like this:
<script>{{ Counter.reset }}</script>
<table>
...
{% for l in list %}
{%if Counter.counter <= 5 %}
<tr><td>{{ l.some_field }} <span style="display:none">{{ Counter.increment }}</span></td></tr>
{% endif %}
{% endfor %}
</table>
So, how can I just call the Counter.increment method, without needing the <span> inside which I encapsulate it (so the output from that code isn't sent to the browser)? Is it okay to just do:
<tr><td>{{ l.some_field }}{{ Counter.increment }}</td></tr>
The above would work, if Counter.increment doesn't return anything, but what if it does?!
How best can the output of executing python code in a Django template be suppressed then?
Also you can use with tag and ignore variable:
{% with ignorevar=Counter.increment %}{% endwith %}
This is a bit of a hack, but it would solve your problem:
{{ Counter.increment|yesno:"," }}
(See the documentation on the yesno filter)
If you only need the top five elements, then I think the right way is to send a list of only top 5 elements from your views to your your html templates in the very first place.
Also, if for some reason, you are not able to do that, then you should there is a thing in Django known as Template Tags where you do all your calculations.
See this -> https://docs.djangoproject.com/en/1.9/howto/custom-template-tags/
And finally if you still want to use Counter.increment, then simply put it inside a div say "count-flag" and using your javascript, hide that div forever on page load:
$(document).on('ready', function(){
$("#count-flag").hide();
}
So it will not be displayed on your html, but technically this is not the way to do it.

How can I use a JSON response in conditional python logic?

I'm using ajax to asynchronously update a boolean variable in my Django project. I'm able to successfully display this variable using the template but I'm not sure how I can use this variable in the template's embedded python logic.
Basically
{% if JSON_BOOL %}
<p>this</p>
{% else %}
<p>that</p>
{% endif %}
Where the JSON_BOOL is being supplied by an ajax function. What's the best way to make the variable available to the conditional logic? Thanks.
There are two ways to solve this. If I were you, I would just leave the variable in text format and in your code say:
{% if JSON_BOOL == "True" %}
...
{% else %}
...the rest of your code
Otherwise you could cast it to a boolean on the python side of things. This would look as follows in your view:
if JSON_BOOL == "True":
JSON_BOOL = True
else:
JSON_BOOL = False
I'm not aware of a way to cast variables to different types within the template itself..this seems to be outside of its scope of functionality, and either way it's better to keep functionality out of templates. Hope this helps.

Jinja Macros: passing the local variables

How can I pass the all local variables in a template to a macro?
I can pass var1, var 2 to macro_function like that in test.html
{% from 'macro.html' import macro_function %}
{{ macro_function(var1, var2) }}
is there something like
{{ macro_function(**locals) }}
so that I can pass all local variables in test.html to the macro?
Not sure why you would want to do that.
I would say keep definitions of template scoped variables to a minimum.
And if you need a set of variables, you can pass a dict or an object holding all relevant key/value pairs from the function that renders the macro. Then in turn pass the dict/object to the macro.

Jinja2 dynamic variable building

My jinja template gets an object which has many variable names, this attributes vary and so their names, I am looking for a way to access this attributes based on a prefix and a for loop:
{% for i in Object.vars %}
<h1> {{ Object.attribute_ + i }} </h1>
{% endfor %}
I'm trying to access Object.attribute_1, Object.attribute_2 and so on. the code above of course won't work, but I can't think on a way of doing this.
Keep in mind that doing too much logic in your template files will cause (long term) issues to maintain your code.
I would say, keep your logic outside of the template and create a list of your objects before rendering the template, using the getattr() function:
for i in Object.vars:
list_of_objects.append(getattr(Object, 'attribute_' + i))
Now when rendering the template pass the list to like that:
render_template('page.html', list_of_objects=list_of_objects)
The canonical way to solve problems like this is to pass a structure such as a list or dict. Dynamic variable names are almost always a terrible idea.

Categories