Jinja2 and Json - python

I have for example a JSON File
{
"Google":{
"Web":"www.web.de",
"Apps":{
"Drive": "DriveLink",
"Dropbox": "DropboxLink"
},
"Google Main":"http://mail.google.com",
"G+":"http://plus.google.com"
},
"Social":{
"Facebook":"http://www.facebook.de",
"G+":"https://plus.google.com",
"Xing":"http://www.xing.de",
"LinkedIn":"http://www.linkedin.com",
"Tumblr":"http://www.tumblr.com"
},
"Fun":{
"Reddit":"http://www.reddit.com"
}
}
As you can see I have under the section Google a Nested Section named Apps
With CherryPy I hand over this JSON Object as following with the name linksList:
#cherrypy.expose
def index(self):
linksFile = open('links.json', 'r')
linksList = json.load(linksFile)
template = jinjaEnv.get_template('index.html')
return template.render(linksList=linksList)
What I want is to render following:
Google
Web (as a link)
Google Main
G+
Apps
Drive
Dropbox
Social
Facebook
G+
Xing
and so on
What I don't understand is to do is to render this nested Objects like "Apps" recursively

The documentation reads:
It is possible to use loops recursively. This is useful if you are
dealing with recursive data such as sitemaps. To use loops recursively
you basically have to add the recursive modifier to the loop
definition and call the loop variable with the new iterable where you
want to recurse.
In your case this would be accomplished with the following:
<ul>
{% for key, value in linksList.items() recursive %}
<li>
{% if value is string %}
{{ key }}
{% else %}
{{ key }}
<ul>{{ loop(value.items()) }}</ul>
{% endif %}
</li>
{% endfor %}
</ul>

My 2 cents, just if someone comes here looking for rendering a JSON using Jinja, and complementing the response from #Ryon Sherman :)
Since JSON may have int values as well as strings, you can use if value is mapping (and flip the if-condition)
If your output must feel like a JSON you can use {{key|indent(width)}} + loop.depth
In my case, the template was for an email and key|indent() didn't work as expected so I ended up using an auxiliar {% for %} loop:
<div>
<code>{
{% for key, value in dic.items() recursive %}
{% if value is mapping %}
<p>
{% for it in range(loop.depth) %} {% endfor %}{{key}}: {
</p>
{{ loop(value.items()) }}
<p>
{% for it in range(loop.depth) %} {% endfor %}}
</p>
{% else %}
<p>
{% for it in range(loop.depth) %} {% endfor %}{{key}}: {{value}},
</p>
{% endif %}
{% endfor %}
}</code>
</div>

Related

Extracting values from a dict - flask and jinja

In my template I have
<p>{% for dict_item in MySQL_Dict %}
{% for key, value in dict_item.items() %}
{{value}}
{% endfor %}
{% endfor %}</p>
Which outputs 43.8934276 -103.3690243 47.052060 -91.639868 How do I keep values i.e. the coordinates together AND have them separated by a comma? Is this possible?
The easiest way is to format it on back-end and pass it the jinja in the way you want. In fact its better to put complex logic on the back-end not the front-end performs better and in jinja's case you don't have to pass in python methods so it's cleaner... other templating frameworks like tornados include all of pythons base functions so you don't have to pass them in like the example below. Another way to do it is to pass the str.join, len, and range method to jinja e.x join=str.join, len=len, range=range then... and I'm guessing MySQL_Dict is a 2d array, hence the double for loop
<p>
{% for dict_item in MySQL_Dict %} // dict_item == [{}, {}, ...]
{% for i in range(len(dict_item)) %} // dict_item[i] == {some object}
{{",".join(dict_item[i]["latitude"], dict_item[i]["longitude"])}}
{% endfor %}
{% endfor %}
</p>

Pass and View Dictionary from view to template in django

I am passing the dictionary to the view but it is now showing on the page.
i also have print the dictionary on the before passing, and it prints the whole dictionary on the screen perfectly. but when i pass it to the html page, it does not show at all..
view.py
def show_log_messages(request):
context = RequestContext(request)
log_dictionary = {}
count = 0
e = log_messages.objects.filter(log_status='Queue').values('sent_to', 'unique_arguments')
count = 0
logs = {}
for d in e:
count +=1
new_dict = {'email': d["sent_to"], 'log_id': d["unique_arguments"]}
logs[count] = new_dict
for keys in logs:
print logs[keys]['log_id']
print logs[keys]['email']
return render_to_response('show_logs.html', logs, context)
show_logs.html
{% if logs %}
<ul>
{% for log in logs: %}
{% for keys in log %}
<li>{{ log[keys]['email'] }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no logs present.</strong>
{% endif %}
it only show the heading not the list element.
Your code is very unpythonic and undjango. You should pass to template a list instead of dictionary.
Also shortcuts.render is much simpler to use than render_to_response.
def show_log_messages(request):
messages = log_messages.objects.filter(log_status='Queue') \
.values('sent_to', 'unique_arguments')
logs = [{'email': msg['sent_to'], 'log_id': msg['unique_arguments']}
for msg in messages]
return render(request, 'show_logs.html', {'logs': logs})
Template:
{% if logs %}
<ul>
{% for log in logs %}
<li>{{ log.email }} - {{ log.log_id }}</li>
{% endfor %}
</ul>
{% else %}
<strong>There are no logs present.</strong>
{% endif %}
BTW, logs list is unnecessary here. You can pass messages queryset directly into template and show {{ log.sent_to }} and {{ log.unique_arguments }} in the <li> tag.
The render_to_response shortcut takes a dictionary. If you want to access logs in the template, it should be in that dictionary:
return render_to_response("show_logs.html", {'logs': logs}, context)
The second problem is that your django template is invalid. It looks like you're trying to write Python in the template. You'd probably find it helpful to read through the Django template language docs.
It's not clear to me what you're trying to display, so here's an example of looping through each log, and displaying its id and email. You should be able to adjust this to get the result you want.
{% if logs %}
{% for key, value in logs.items %}
{{ key }}, {{ key.log_id}}, {{ key.email }}
{% endf
{% else %}
<strong>There are no logs present.</strong>
{% endif %}

flask and wtf - how can I direct tag attributes for fields?

After fiddling with wtforms, fields use widgets to actually render them to html. I wrote some custom field/widget to draw html in a way that I'd more like to. But here's a question:
suppose I want to render them with pre-defined css class or give actual details myself.
How can I achieve this? and on what phase of handling requests(at Form class declaration? or when setting attributes to give Form some Fields? or when I'm actually calling them in jinja2 templates) I should do that?
I use a Jinja macro something like this:
{% macro field_with_errors(field) %}
{% set css_class=kwargs.pop('class', '') %}
{% if field.type in ('DateField', 'DateTimeField') %}
{{ field(class='date ' + css_class, **kwargs) }}
{% elif field.type == 'IntegerField' %}
{{ field(class='number ' + css_class, **kwargs) }}
{% else %}
{{ field(class=css_class, **kwargs) }}
{% endif %}
{% if field.errors %}
<ul class="errors">{% for error in field.errors %}<li>{{ error|e }}</li>{% endfor %}</ul>
{% endif %}
{% endmacro %}
usage is something like:
{{ field_with_errors(form.foo, placeholder='bar') }}
This lets me avoid boilerplate, but also lets me keep the display decisions in the template space.
Have a look at the rendering fields section.
Alternatively, you can add attributes to be rendered in the Jinja2 (etc.) template:
<div class="input-prepend">
{{ form.address(placeholder="example.com", id="address", autofocus="autofocus", required="required") }}
</div>
There's nothing to prevent you from using a variable for the ID value above, instead of address, then rendering the template with a keyword argument to populate it.

What are some useful non-built-in Django tags?

I'm relatively new to Django and I'm trying to build up my toolbox for future projects. In my last project, when a built-in template tag didn't do quite what I needed, I would make a mangled mess of the template to shoe-horn in the feature. I later would find a template tag that would have saved me time and ugly code.
So what are some useful template tags that doesn't come built into Django?
I'll start.
http://www.djangosnippets.org/snippets/1350/
Smart {% if %} template tag
If you've ever found yourself needing more than a test for True, this tag is for you. It supports equality, greater than, and less than operators.
Simple Example
{% block list-products %}
{% if products|length > 12 %}
<!-- Code for pagination -->
{% endif %}
<!-- Code for displaying 12 products on the page -->
{% endblock %}
smart-if. Allows normal if x > y constructs in templates, among other things.
A better if tag is now part of Django 1.2 (see the release notes), which is scheduled for release on March 9th 2010.
James Bennet's over-the-top-dynamic get_latest tag
edit as response to jpartogi's comment
class GetItemsNode(Node):
def __init__(self, model, num, by, varname):
self.num, self.varname = num, varname
self.model = get_model(*model.split('.'))
self.by = by
def render(self, context):
if hasattr(self.model, 'publicmgr') and not context['user'].is_authenticated():
context[self.varname] = self.model.publicmgr.all().order_by(self.by)[:self.num]
else:
context[self.varname] = self.model._default_manager.all().order_by(self.by)[:self.num]
return ''
<div id="news_portlet" class="portlet">
{% get_sorted_items cms.news 5 by -created_on as items %}
{% include 'snippets/dl.html' %}
</div>
<div id="event_portlet" class="portlet">
{% get_sorted_items cms.event 5 by date as items %}
{% include 'snippets/dl.html' %}
</div>
I call it get_sorted_items, but it is based on James' blog-post
In come case {% autopaginate queryset %} (http://code.google.com/p/django-pagination/) is useful. For example:
#views.py
obj_list = News.objects.filter(status=News.PUBLISHED)
# do not use len(obj_list) - it's evaluate QuerySet
obj_count = obj_list.count()
#news_index.html
{% load pagination_tags %}
...
# do not use {% if obj_list %}
{% if obj_count %}
<div class="news">
<ul>
{% autopaginate obj_list 10 %}
{% for item in obj_list %}
<li>{{ item.title }}</li>
{% endfor %}
</ul>
</div>
{% paginate %}
{% else %}
Empty list
{% endif %}
Note, that obj_list must be lazy - read http://docs.djangoproject.com/en/dev/ref/models/querysets/#id1

How do I access a python list from a django templatetag?

I have created a templatetag that loads a yaml document into a python list. In my template I have {% get_content_set %}, this dumps the raw list data. What I want to be able to do is something like
{% for items in get_content_list %}
<h2>{{items.title}}</h2>
{% endfor %}`
If the list is in a python variable X, then add it to the template context context['X'] = X and then you can do
{% for items in X %}
{{ items.title }}
{% endfor %}
A template tag is designed to render output, so won't provide an iterable list for you to use. But you don't need that as the normal context + for loop are fine.
Since writing complex templatetags is not an easy task (well documented though) i would take {% with %} tag source and adapt it for my needs, so it looks like
{% get_content_list as content %
{% for items in content %}
<h2>{{items.title}}</h2>
{% endfor %}`

Categories