Is there a generic, recursive flask template? - python

As a way to rapidly prototype an html ui, I am looking for a generic jinja2 template, that will display an object's or dictionary name/value pairs recursively, including drilling into sub objects recursively.
So say I had this dictionary:
a_dict = {'name1': 'value1', 'name2': 'value2'}
a_dict['other'] = {'name3': 'value3', 'name4': 'value4'}
It would display something like this:
name1: value1
name2: value2
other:
name3: value3
name4: value4

{% macro show_node(node) %}
{% for key, value in node.__dict__.items() %}
<span>{{key}}: </span>
{% if value is mapping %} <-- not sure what to do here
{{ show_node(value) }}
{%else%}
<span>Value: {{value}}</span>
{% endif %}
{% endfor %}
{% endmacro %}
there you go

Related

I want to print both, keys and values of dictionary which I pass in render to a HTML page in Django

This loop format in html is only printing the key but not value,I want to print both key and value in html page.
views.py
def predict(request):
if request.method == "POST":
dict = {'Name': John, 'Age': 40}
return render(request,'standalone.html',{'content':dict})
else:
return render(request,'test_homepage.html')
satandalone.html
{% for c in content %}
{{c}}
{% endfor %}
You use .items() to obtain an iterable of 2-tuples.
def predict(request):
if request.method == "POST":
data = {'Name': 'John', 'Age': 40}
return render(request,'standalone.html',{'content': data.items()})
else:
return render(request,'test_homepage.html')
In the template, you can then render this with:
{% for k, v in content %}
{{ k }}: {{ v }}
{% endfor %}
Note: Please do not name a variable dict, it overrides the reference to the dict
class. Use for example data.
Try this in your template satandalone.html:
{% for c in content %}
{{ c.name }}
{{ c.age }}
{% endfor %}
Try this. It might help you.
{% for key, value in content.items %}
{{ key }}: {{ value }}
{% endfor %}

Access dictionary within dictionary jinja

I have a list of dictionaries called data.
for every_archive in data I want to acces every_archive['key1']['key2']
First key it's a constant: "units" but the second key depends on a loop.
I have already tried : {{ archive['units'][{{item['param']}}] }}
where item['param'] item is another iterator in a loop and item['param'] is the second key.
See the format below! The structure is going to be very similar to how you would loop through a dictionary in Python, but with the jinja {% %} for each statement you do not want to display and {{ }} around each expression you want to display.
Taken from How to iterate through a list of dictionaries in jinja template?
Data: parent_dict = [{'A':{'a':1}},{'B':{'b':2}},{'C':{'c':3}},{'D':{'d':4}}]
In Jinja2 iteration:
{% for dict_item in parent_dict %}
{% for key1 in dict_item %}
{% for key2 in dict_item[key1] %}
<h2>Value: {{dict_item[key1][key2]}}</h2>
{% endfor %}
{% endfor %}
{% endfor %}
As far as I understood, you have a list that contains some nested dictionaries; if that's the case, and your data looks like that:
data = [{'foo': {'bar1': 'buzz1', 'bar2': 'buzz2'}}, {'foo': {'bar3': 'buzz3', 'bar4': 'buzz4'}}]
if you use this Jinja2:
{% for every_archive in data %}
{% for key1, archive1 in every_archive.items() %}
{% for key2, value2 in archive1.items() %}
<p>{{ key1 }} - {{ key2 }} - {{ value2 }}</p>
{% endfor %}
{% endfor %}
{% endfor %}
you will get this output:
foo - bar1 - buzz1
foo - bar2 - buzz2
foo - bar3 - buzz3
foo - bar4 - buzz4
also, the same output you will get from
<p>{{ key1 }} - {{ key2 }} - {{ archive1[key2] }}</p>

Determining if I need quotes in HTML with django template

I have a dict in python that is something like the following:
d = {'key1': .98, 'key2': 'some_str',
#...
}
In this dictionary some keys will be mapped to float and others will be mapped to str
In my HTML I am doing something like the following:
html_dict = {
{% for k, v in my_dict.items %}
{{ k }}: "{{ v }}",
{% endfor %}
};
However this approach wraps the floats in quotes as well, which is what I don't want. But if I don't know wrap them in quotes the HTML doesn't understand that they are are string values. I would ideally like something like the following:
html_dict = {
{% for k, v in my_dict.items %}
{% if check_v_is_str %}
{{ k }}: "{{ v }}",
{% else %}
{{ k }}: {{ v }},
{% endif %}
{% endfor %}
};
Don't do this. You are manually trying to replicate a JS data structure, when there already exists a well-defined structure that both Python and JS know about, namely JSON. Use that instead. Convert the dict to JSON in your view, and pass it to the template where it can be output directly.
You could define a filter called "check_v_type" to call in your template as follows:
{% if v|check_v_type == 'str' %}
But I don't think that makes for good logic. Generally, you want to avoid function calls in your templates. Instead, in your view, you could create a dictionary of tuples of the form:
d = {'key1': (.98, False), 'key2': ('some_str', True), #...}
You could then use the boolean in each tuple to decide how to format the value in your HTML.

Django template and part of a dictionary of lists

in Django I want to display some entries in a dictionary of lists.
My context is:
keys = ['coins', 'colors']
dict = {'colors':['red', 'blue'],
'animals':['dog','cat','bird'],
'coins':['penny','nickel','dime','quarter'] }
Template code:
<ul>{% for k in keys %}
<li>{{ k }}, {{ dict.k|length }}: [{% for v in dict.k %} {{ v }}, {% endfor %}]
{% endfor %}</ul>
I want to see:
* coins,4: [penny, nickel, dime, quarter,]
* colors,2: [red, blue,]
But what I actually see is keys but no values:
* coins,0: []
* colors,0: []
Note: I also tried dict.{{k}} instead of dict.k, but as expected that just gave a parse error in template rendering. I'll get rid of the trailing comma with forloop.last after getting the basic list working.
What is the secret sauce for displaying selected values from a dictionary of lists?
The question django template and dictionary of lists displays an entire dictionary, but my requirement is to display only a few entries from a potentially very large dictionary.
The problem (as you suspected) is that dict.k is evaluated to dict['k'] where 'k' is not a valid key in the dictionary. Try instead to iterate each item pair using dict.items and only display the results for the keys you're concerned with:
<ul>{% for k, v in dict.items %}
{% if k in keys %}
<li>
{{ k }}, {{ v|length }}: [{% for val in v %} {{ val }},{% endfor %}]
</li>
{% endif %}
{% endfor %}
</ul>
<ul>
{% for k, v in dict.items %} # instead of iterating keys, iterate dict
{% if k in keys %} # if key found in keys
<li>
{{ k }}, {{ v|length }}: [{% for val in v %} {{ val }},{% endfor %}]
</li>
{% endif %}
{% endfor %}
</ul>

jinja2 recursive loop vs dictionary

I have the following dictionary:
{'a': {'b': {'c': {}}}}
And the following Jinja2 template:
{% for key in dictionary recursive %}
<li>{{ key }}
{% if dictionary[key] %}
<ul>{{ loop(dictionary[key]) }}</ul>
{% endif %}
</li>
{% endfor %}
But Jinja2 always output:
<ul>
<li>a</li>
<ul>
<li>b</li>
</ul>
</ul>
My understood is that using recursive, it would show me the "c" element too, but it only works for a depth of 2. Why is dictionary not changing to the dictionary[key] at every loop iteration ? The dictionary is always the original dictionary.
You're right, dictionary isn't being updated in the recursion calls, and the loop cannot continue because the keys aren't found.
A workaround to this problem is using just the variables assigned in the for loop. In the dictionary example, this means to iterate through the items of the dictionary instead of just the keys:
from jinja2 import Template
template = Template("""
{%- for key, value in dictionary.items() recursive %}
<li>{{ key }}
{%- if value %}
Recursive {{ key }}, {{value}}
<ul>{{ loop(value.items())}}</ul>
{%- endif %}
</li>
{%- endfor %}
""")
print template.render(dictionary={'a': {'b': {'c': {}}}})
The output of this script is:
<li>a
Recursive a, {'b': {'c': {}}}
<ul>
<li>b
Recursive b, {'c': {}}
<ul>
<li>c
</li></ul>
</li></ul>
</li>
where you can see that recursion on the b key works fine because both key and value are updated on each iteration of the loop (I added the "Recursive key, value" message to the template to make it clear).
try something like this:
{% for key in dictionary recursive %}
<li>{{ key }}
{% if dictionary[key] %}
<ul>{{ loop(dictionary[key].keys()) }}</ul>
{% endif %}
</li>
{% endfor %}
I think you need to pass an iterable into the loop() construct.

Categories