How to parse the following dict in django templates? - django

I have a following dict structure passed to my Django template, whose keys or length are unknown to me:
config_values = {
'Kafka': {
'KAFKA_BROKER_URL': 'localhost:9092',
},
'Redis': {
'REDIS_HOST': 'localhost',
'REDIS_PORT': '6379',
},
}
I want to show it in my templates as shown below
Kafka
KAFKA_BROKER_URL = localhost:9092
Redis
REDIS_HOST = localhost
REDIS_PORT = 6379
I'm relatively new to python and dicts.

You can iterate through a dict in a django template just the way you do in python.
Look at this.
{% for i,j in config_file.items %}
{{i}} // i will give you 'kafka'
{% for k,l in j.items %}
{{k}} {{l}} // k will give you 'kafka_broker_url' and l will give you localhost:9092
{% endfor %}
{% endfor %}

Related

Was wondering why iterating through a dictionary using .keys in django would not work?

I know that .items would be useful to grab the value, but wanted to see why this would not work?
Data:
...
city_data = {
'city': json_data['name'],
'country': json_data['sys']['country'],
'temp': json_data['main']['temp'],
'feels_like': json_data['main']['feels_like'],
'temp_max': json_data['main']['temp_max'],
'temp_min': json_data['main']['temp_min']
}
return render(request, ..., context={'city_data':city_data})
template:
...
{% for key in city_data.keys %}
<li>{{city_data.key}}</li>
{% endfor %}
...
I think that the reason that it doesn't work that way is because django will look at test.key and try to look up a string "key" as an actual key to the dictionary. There are a couple ways that you could do this. One way is you could define a custom template filter that would allow you to do it. I don't know much about custom filters so I can't say how specifically to do it. Another way though is to use city_data.items in your template instead like this:
{% for key,value in city_data.items %}
<li>{{ value }}</li>
{% endfor %}

Jinja2 is treating list of dictionary as string

I am using ansible to parse a jinja2 template. The jinja2 template has a piece of code which should iterate over a variable which is a list of dicts. However it is treating the list of dict as string and printing the individual characters. Please note the variable is set_fact in the ansible playbook.
Code to loop on the list of dicts in the j2 template:
{% for subscriber in subscribers %}
{% for dict_item in subscriber['filter_policy'] %}
{{dict_item.name}}
{% endfor %}
{% endfor %}
Variable as output in the debug module of ansible:
subscribers": [
{
"filter_policy": "[ { \"name\": \"Severity\", \"type\": \"CommaDelimitedList\", \"value\": \"critical\" }, { \"name\": \"Environment\", \"type\": \"CommaDelimitedList\", \"value\": \"nonprod\" }]",
"id": "blah#blah.com"
}
]
Ansible gives me an error saying:
"msg": "AnsibleUndefinedVariable: 'str object' has no attribute 'name'"
However if I use set in the jinja2 template to assign the same value to the variable and use for loop over it, it works fine.
{% set policies = [{"name": "Severity","type": "CommaDelimitedList","value": "critical"},{"name": "Environment","type": "CommaDelimitedList","value": "nonprod"}] %}
I have no clue, how to resolve it.
ansible 2.7.2
python version = 3.7.3 (default, Mar 27 2019, 09:23:39) [Clang 10.0.0 (clang-1000.11.45.5)]
Your filter_policy variable effectively contains a string which happens to be a json representation of a list of dicts. You just have to decode that json string to an effective list of dicts with the from_json filter
{% for subscriber in subscribers %}
{% for dict_item in (subscriber['filter_policy'] | from_json) %}
{{dict_item.name}}
{% endfor %}
{% endfor %}

What's the most DRY way to disable a link to the current page?

In my Django web-app, I want to let users sort model objects by different parameters, which I achieve with URL parameters which tell the view which items should be loaded. Here's the Jinja/HTML snippet from the template:
<p><b><span class="text-info">sort by:</span></b>
latest_release |
alphabetically |
soonest release</p>
If the user is already sorting by latest_release (the first link), I want the link from it removed. However, I can't seem to find a way to do this in a DRY way.
You can define dict in your view with argument name - display name mapping:
mapping = {'': 'latest_release', 'name': 'alphabetically', 'next_release': 'soonest release'}
and pass it to context:
context['mapping'] = mapping
Now in template iterate over each pair from dict and show link only if sorted_by value not equal with key:
{% for k, v in mapping.items %}
{% if request.GET.sorted_by|default:"" != k %} {{ v }} |{% endif %}
{% endfor %}
To remove | delimiter after last link you can validate forloop.last status.

How can I access items within a ndb query object clientside?

I'm working with appengine, django and webapp2 and am sending a query object clientside such that
{{ exercise_steps }}
returns
Query(kind='ExStep')
and
{{ exercise_steps.count }}
returns 4
I'm trying to chuck the variable exercise_steps into some javascript code and need to iterate through the items in a javascript (not a django) loop but I cannot seem to access the items.
I've tried {{ exercise_steps|0 }}, {{ exercise_steps[0] }}, {{ exercise_steps.0 }} but it returns nothing. I know I can do this with a django loop but is there a way I can access the objects within the query with a javascript loop using something like
for (var i = 0; i < {{exercise_steps.count}}; i++) {
console.log({{ exercise_steps.i.location }})
}
You can't mix client side code and template code... by the time the javascript runs, your python code is already executed. You are not sending a python object to the javascript - it's executed when the HTML is generated.
You need to recreate array in JS, or have an ajax call return an array from python.
var steps = [
{% for step in exercise_steps %}
{{ step.location }}{% if not forloop.last %},{% endif %}
{% endfor %}]; // now your python iterable is a JS array.

Need to convert a string to int in a django template

I am trying to pass in url parameters to a django template like this...
response = render_to_string('persistConTemplate.html', request.GET)
This the calling line from my views.py file. persistConTemplate.html is the name of my template and request.GET is the dictionary that contains the url parameters.
In the template I try to use one of the parameters like this...
{% for item in (numItems) %}
item {{item}}
{% endfor %}
numItems is one of the url parameters that I am sending in my request like this...
http:/someDomain/persistentConTest.html/?numItems=12
When I try the for loop above, I get an output like this....
image 1 image 2
I am expecting and would like to see the word image printed 12 times...
image 1 image 2 image 3 image 4 image 5 image 6 image 7 image 8 image 9 image 10 image 11 image 12
Can anyone please tell me what I am going wrong?
you can coerce a str to an int using the add filter
{% for item in numItems|add:"0" %}
https://docs.djangoproject.com/en/dev/ref/templates/builtins/#add
to coerce int to str just use slugify
{{ some_int|slugify }}
EDIT: that said, I agree with the others that normally you should do this in the view - use these tricks only when the alternatives are much worse.
I like making a custom filter:
# templatetags/tag_library.py
from django import template
register = template.Library()
#register.filter()
def to_int(value):
return int(value)
Usage:
{% load tag_library %}
{{ value|to_int }}
It is for cases where this cannot be easily done in view.
Yes, the place for this is in the view.
I feel like the above example won't work -- you can't iterate over an integer.
numItems = request.GET.get('numItems')
if numItems:
numItems = range(1, int(numItems)+1)
return direct_to_template(request, "mytemplate.html", {'numItems': numItems})
{% for item in numItems %}
{{ item }}
{% endfor %}
The easiest way to do this is using inbuilt floatformat filter.
For Integer
{{ value|floatformat:"0" }}
For float value with 2 precision
{{ value|floatformat:"2" }}
It will also round to nearest value. for more details, you can check https://docs.djangoproject.com/en/1.10/ref/templates/builtins/#floatformat.
You should add some code to your view to unpack the GET params and convert them to the values you want. Even if numItems were an integer, the syntax you're showing wouldn't give you the output you want.
Try this:
ctx = dict(request.GET)
ctx['numItems'] = int(ctx['numItems'])
response = render_to_string('persistConTemplate.html', ctx)
In my case one of the items was a string and you can not compare a string to an integer so I had to coerce the string into an integer see below
{% if questions.correct_answer|add:"0" == answers.id %}
<span>Correct</span>
{% endif %}
You can do like that: if "select" tag used.
{% if i.0|stringformat:'s' == request.GET.status %} selected {% endif %}
My solution is kind of a hack and very specific..
In the template I want to compare a percentage with 0.9, and it never reaches 1, but all the values are considered string in the template, and no way to convert string to float.
So I did this:
{% if "0.9" in value %}
...
{% else %}
...
{% endif %}
If I want to detect some value is beyond 0.8, I must do:
{% if ("0.9" in value) or ("0.8" in value) %}
...
{% else %}
...
{% endif %}
This is a hack, but suffice in my case. I hope it could help others.