I need to represent collection in the template and wrap every four elements in the
<li></li>
The template should be like this:
<ul>
<li>
<a></a>
<a></a>
<a></a>
<a></a>
</li>
<li>
<a></a>
<a></a>
<a></a>
<a></a>
</li>
<li>
<a></a>
<a></a>
<a></a>
<a></a>
</li>
</ul>
So i need to do it in the {% for %}
{% for obj in objects %}
{#add at 1th and every 4th element li wrap somehow#}
<a>{{object}}</a>
{# the same closing tag li#}
{% endfor %}
The following should solve your problem, using built-in template tags :
<ul>
<li>
{% for obj in objects %}
<a>{{ obj }}</a>
{# if the the forloop counter is divisible by 4, close the <li> tag and open a new one #}
{% if forloop.counter|divisibleby:4 %}
</li>
<li>
{% endif %}
{% endfor %}
</li>
</ul>
You can use the divisibleby tag as mentioned before, but for template clearing purposes I usually prefer a helper function that returns a generator:
def grouped(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]
example simplistic view:
from app.helpers import grouped
def foo(request):
context['object_list'] = grouped(Bar.objects.all(), 4)
return render_to_response('index.html', context)
example template:
{% for group in object_list %}
<ul>
{% for object in group %}
<li>{{ object }}</li>
{% endfor %}
</ul>
{% endfor %}
you can use divisibleby built-in filter, here is link to django documentation
so something like this would work
{% if value|divisibleby 4 %}
#your conditional code
{% endif %}
if you want to work it with checking first forloop and last forloop you could use this :
<ul>
{% for obj in objects %}
{% if forloop.first %}
<li>
{% endif %}
<a>{{obj}}</a>
{% if forloop.counter|divisibleby:4 and not forloop.first %}
</li>
<li>
{% endif %}
{% if forloop.last %}
</li>
{% endif %}
{% endfor %}
</ul>
I personally would consider to separate the elements in the view before passing them to the template and then using nested for loops. Except this you really only have the filter or templatetag option as Vaibhav Mishra mentioned.
Related
How can I filter content like 0-9 then 9-18 then 18-28 and so on.. in Django using a slice filter or any other option?, SO please suggest me.
<li class="mega-title"><span>column 01</span>
<ul>
{% for category in categories %}
{% for subcategory in category.children.all|slice:":9" %}
<li>{{subcategory.title}}</li>
{% endfor %}
{% endfor %}
</ul>
</li>
<li class="mega-title"><span>column 02</span>
<ul>
{% for category in categories %}
{% for subcategory in category.children.all|slice:"[09:9]" %}
<li>{{subcategory.title}}</li>
{% endfor %}
{% endfor %}
</ul>
</li>
Django slice filter: https://docs.djangoproject.com/en/dev/ref/templates/builtins/#slice
{% for subcategory in category.children.all|slice:":9" %}
{% for subcategory in category.children.all|slice:"10:18" %}
....
In my Django project I use django-mptt application to create hierarchical tree. Right now next code works well but I want to show only first 4 level of the tree. How to make it correctly? I am confused.
views.py:
context['caregories'] = Category.objects.get(id=5).get_descendants()
html:
{% load mptt_tags %}
<ul>
{% recursetree caregories %}
<li>
{{ node.name }}
{% if not node.is_leaf_node %}
<ul class="children">
{{ children }}
</ul>
{% endif %}
</li>
{% endrecursetree %}
</ul>
You can filter the descendants by their level
obj = Category.objects.get(id=5)
context['caregories'] = obj.get_descendants().filter(level__lte=obj.level + max_depth)
where max_depth is the depth you require
I'm trying to have two separate menus in my django-cms app. One for the header and another with a different set of links for the footer:
[ Logo ] Link_A Link_B Link_C Link_D
... content ...
Link_E Link_F Link_G Link_H
Using baked in {% show_menu %}, will show all of the pages registered, links A - H, and doesn't allow me to separate the two menus.
How can I create two separate menus?
Depends what you want to do really, but I've got a base template which has a navigation menu at the top and a sitemap submenu at the bottom.
So starting with the navigation;
{% show_menu 1 100 100 100 "partials/navigation.html" %}
Which uses the template;
{% load cms_tags menu_tags cache cms_page %}
{% for child in children %}
<li>
<a href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">
{{ child.get_menu_title }}
</a>
{% if child.children and child.level <= 4 %}
<ul>
{% show_menu from_level to_level extra_inactive extra_active template '' '' child %}
</ul>
{% endif %}
</li>
{% endfor %}
Then the sitemap;
{% show_sub_menu 2 1 1 "partials/sitemap.html" %}
And sitemap.html
{% load cms_tags cms_page cache %}
{% if children %}
{% for child in children %}
<ul class="site-footer__column">
<li>
<h4>
<a href="{{ child.attr.redirect_url|default:child.get_absolute_url }}">
{{ child.get_menu_title }}
</a>
</h4>
</li>
{% if child.children %}
{% for baby in child.children %}
<li class="footer_sub">
<a href="{{ baby.attr.redirect_url|default:baby.get_absolute_url }}">
{{ baby.get_menu_title }}
</a>
</li>
{% endfor %}
{% endif %}
</ul>
{% endfor %}
{% endif %}
Understanding the options (numbers) you can provide for a menu can enable you to display different parts of your site, but if the built in menu tags don't suit your needs, you could write a custom menu tag.
The standard menu docs are here; http://docs.django-cms.org/en/3.2.2/reference/navigation.html
And here are the docs for customising your menus; http://docs.django-cms.org/en/3.2.2/how_to/menus.html
I have the following loop in my Django template:
{% for item in state.list %}
<div> HTML (CUSTOMERS BY STATE) </div>
<!-- print sum of customers at bottom of list -->
{% if forloop.last %}
<h4>{{ forloop.counter }} Valued Customers</h4>
{% endif %}
{% endfor %}
Obviously, if I end up with only one customer, I'd like to print singular "Valued Customer"
According to Django's docs, one should use blocktrans. Tried the following, a few flavors of nesting:
{% blocktrans count %}
{% if forloop.last %}
<h4>
{{ forloop.counter }}
Valued Customer
{% plural %}
Valued Customers
</h4>
{% endif %}
{% endblocktrans %}
Keep getting TemplateSyntaxError: Invalid block tag: 'blocktrans', expected 'empty' or 'endfor'
Is there no way to combine with another loop? Any ideas how to solve? Thanks!
Here is the working code, thanks to alko:
{% load i18n %}
<!-- ... -->
{% if forloop.last %}
<h4>
{{ forloop.counter }}
{% blocktrans count count=forloop.counter %}
Valued Customer
{% plural %}
Valued Customers
{% endblocktrans %}
</h4>
{% endif %}
Probably, you forgot to load translation tags. Add following line at the top of your template:
{% load i18n %}
After you fix that, note that for a blocktrans tag after count a variable, whose value will serve for plural detection, should be specified, so you probably need something like
{% blocktrans count count=forloop.counter %}
To pluralize use this:
Customer{{ forloop.counter|pluralize }}
I'd like to replace the standard Markdown implementation in a Django blog I'm building with Github-flavoured Markdown. I'd like to use Misaka, and I've thrown together my own custom template tags. Unfortunately, something has gone awry.
Here is my template tags file, which is in blog/templatetags/gfm.py. The __init__.py file is present in the same folder:
from django import template
from django.template.defaultfilters import stringfilter
import misaka as m
register = template.Library()
#register.filter(is_safe=True)
#stringfilter
def gfm(value):
rendered_text = m.html(value,
extensions=m.EXT_FENCED_CODE,
render_flags=m.HTML_ESCAPE)
return rendered_text
And here is one of my templates:
{% extends 'layout/base.html' %}
{% block header %}
{% endblock %}
{% block content %}
{% load gfm %}
{% if object_list %}
{% for post in object_list %}
<div class="post">
<div class="page-header">
<h1>{{ post.title }}</h1>
</div>
{{ post.text|gfm }}
<p>Posted {{ post.pub_date }}</p>
<p>
{% for category in post.categories.all %}
<a class="badge badge-info" href="/category/{{ category.slug }}/">{{ category.title }}</a>
{% endfor %}
</p>
</div>
{% endfor %}
<br />
<ul class="pager">
{% if page_obj.has_previous %}
<li class="previous">Previous Page</li>
{% endif %}
{% if page_obj.has_next %}
<li class="next">Next Page</li>
{% endif %}
</ul>
{% else %}
<div class="post">
<p>No posts matched</p>
</div>
{% endif %}
{% endblock %}
The outputted text is being returned wrapped in double quotes, which breaks the whole thing. Otherwise, the markup generated seems correct.
Where have I gone wrong here? I know it's not the data in the database as if I use pdb to get the values of value and rendered_text inside the function, they are rendered correctly. For example, here is the plain text version of one post, as printed by pdb:
u'A Python application:\r\n\r\n print "Hello world"'
And here is the version rendered in Markdown using Misaka:
u'<p>A Python application:</p>\n\n<pre><code>print "Hello world"\n</code></pre>\n'
I'm fairly experienced with Django, but I'm new to custom template tags.
Use autoescape tag.
{% autoescape off %}{{ post.text|gfm }}{% endautoescape %}
Alternatively you can use safe filter.
{{ post.text|gfm|safe }}