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.
Related
I am having a hard time with some django errors that have appeared in my code. These errors have raised (I think) when I upgraded from python 2.7 to python 3.6.
The errors are caused because some functions return a string instead of his primitive value. For example in a template in which I have html that should only be shown to superusers I have been using:
{% if user.is_superuser %}
This call should return an 0 (false) or 1, (true) whether the user is superuser or not.
But now this is not working as expected, because it returns '0' or '1'.
I must then parse to int the call to get the proper result:
{% if int.user.is_superuser %}
I find this very unsettling solution. This shouldn't behave like this and there are more internal functions I had to fix because behave in the same fashion.
I am currently using Django 2.2.3 and python 3.6.
Any help for a clean solution is much appreciated.
{% if user.is_superuser %}
<!-- html block -->
{% endif %}
this statement is a condition in Django template like a simple if clause in python
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.
I'm passing to Django's template a function, which returns some records.
I want to call this function and iterate over its result.
{% for item in my_func(10) %}
That doesn't work.
I've tried to set the function's return value to a variable and iterate over the variable, but there seems to be no way to set a variable in a Django template.
Is there any normal way to do it?
You cannot call a function that requires arguments in a template. Write a template tag or filter instead.
if you have an object you can define it as #property so you can get results without a call, e.g.
class Item:
#property
def results(self):
return something
then in the template:
<% for result in item.results %>
...
<% endfor %>
I'm passing to Django's template a function, which returns me some records
Why don't you pass to Django template the variable storing function's return value, instead of the function?
I've tried to set fuction's return value to a variable and iterate over variable, but there seems to be no way to set variable in Django template.
You should set variables in Django views instead of templates, and then pass them to the template.
By design, Django templates cannot call into arbitrary Python code. This is a security and safety feature for environments where designers write templates, and it also prevents business logic migrating into templates.
If you want to do this, you can switch to using Jinja2 templates (http://jinja.pocoo.org/docs/), or any other templating system you like that supports this. No other part of django will be affected by the templates you use, because it is intentionally a one-way process. You could even use many different template systems in the same project if you wanted.
What you could do is, create the "function" as another template file and then include that file passing the parameters to it.
Inside index.html
<h3> Latest Songs </h3>
{% include "song_player_list.html" with songs=latest_songs %}
Inside song_player_list.html
<ul>
{% for song in songs %}
<li>
<div id='songtile'>
<a href='/songs/download/{{song.id}}/'><i class='fa fa-cloud-download'></i> Download</a>
</div>
</li>
{% endfor %}
</ul>
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.
I have a Jinja2 template page which contains two separate {% for %} loops. If neither of these loops contain any items, I want the page to redirect.
I'm trying to do something like this (pseudo-code):
loop1 = loop.length (in first loop)
loop2 = loop.length (in second loop)
if loop1 + loop2 == 0: redirect # (outside both loops)
Is this even possible? Is there a way to make the loop.length variables available outside their respective loops?
You can check your lists for truth, empty lists are false in Jinja2.
{% if things %}
{% for thing in things %} .... {% endfor %}
{% else %}
<!-- redirect here -->
{% endif %}
The simple answer is "no": You can't re-direct using a template -- it should be in the view logic of the controller/server.
Although technically one can, but not doing anyone any favours.
Assuming both things are lists, you can do this:
{% set all_things = thing1 + thing2 %}
{% if all_things %}
{# There is more than one thing in the two lists #}
{% else %}
{# redirect #}
That being said, this is not something that belongs at the template level - you are generating another list containing all of the things in thing1 and thing2 every time you hit the page, which will cost in terms of resources. You are putting application logic in the template level, which will not be maintainable. And finally, you are papering over the larger problem - that making changes to the back end code is costly. (Please understand that "you" in all these cases is the generic "you" - as in "the company you work for").
You (specifically) should raise these issues with those who are asking you to implement this hack and try to change the direction that this tool / product / company is taking before it becomes a piece of FrankenCode.
Good luck!
You could check the length things object(the object you are looping through) by using the length filter:
{{things|length}}
Now to answer your question. lets assume the objects you loop through is named t1 and t2, you could do:
{% if t1 | length == 0 and t2 | length == 0 %}
//use javascript to redirect(assuming you have the link)
{% endif %}
You could do this in your JavaScript block. I do not know if this is the most efficient way to do it, but, it should work.
I am posting this answer, because there is no up-voted or accepted answer to this question.
I do Hope this helps.