OverIQ.com

Template tags in Django

Last updated on July 27, 2020


In the previous chapter, we have already introduced you to some of the basic template tags and filters. In this lesson, we will discuss some important built-in template tags in detail.

if tag #

The following is the syntax of the {% if %} tag:

Syntax:

1
2
3
{% if condition %}
    <p>Print this line</p>
{% endif %}

Here is how it works:

The {% if %} tag evaluates the value of the condition and if it is true (a variable in Python evaluates to true, if it contains a non empty value or non False Boolean value) then the template system will display everything between {% if %} and {% endif %}. For example:

1
2
3
{% if var %}
    <p>Print this para</p>
{% endif %}

If the value of var is 10 then <p>Print this para</p> will be printed. On the other hand, if the value of p is [] (an empty array) or {} (an empty dictionary) or 0 (numerical zero) or False (a Boolean false) then nothing will be printed.

It is important to close each {% if %} with a corresponding {% endif %}. Otherwise, Django will throw TemplateSyntaxError exception.

You can also add an optional {% else %} tag to the {% if %} tag like this:

1
2
3
4
5
{% if var %}
    <p>Print this para</p>
{% else %}
    <p>Else print the other para</p>
{% endif %}

Here is how it works:

First, the value of var is evaluated, if it is true then <p>Print this para</p> will be printed. Otherwise, <p>Else print the other para</p> will be printed.

You can also add one or more {% elif %} clauses to add some more conditions. For example:

1
2
3
4
5
6
7
8
9
{% if count < 10 %}
    <p>Print this para</p>
{% elif count < 20 %}    
    <p>Otherwise print this</p>
{% elif count < 30 %}
    <p>Let's try this</p>
{% else %}
    <p>Okay everything failed print this now</p>
{% endif %}

Here is how it works:

Each condition is evaluated in turn, as soon as one found to be true the code in the corresponding block is executed and evaluation of all the other conditions is skipped.

Comments #

Django template uses the following syntax to write comments.

{# This is a comment #}

The comment you write using this syntax will not be rendered in the HTML source code. Further, you can't expand this comment to multiple lines.

1
2
{# This is
not a comment #}

If you want to write comments in multiple lines use the {% comment %} tag:

1
2
3
4
{% comment %}
This is a comment expanding to
multiple lines.
{% endcomment %}

Using Logical Operators #

You can also use logical and, or and not operators to test multiple conditions. For example:

and operator #

1
2
3
{% if palindrome and even %}
    <p>Number is palindrome and even</p>
{% endif %}

If both variables evaluate to true, then <p>Number is palindrome and even</p> will be printed. Otherwise, nothing would be printed.

not operator #

1
2
3
{% if not post_list %}
    <p>There are no blog post</p>
{% endif %}

The not operator negates the condition. So the above code would print <p>There are no blog posts</p> only when post_list is False (or empty). In other words, if there are no blog posts print <p>There are no blog posts</p>.

or operator #

1
2
3
{% if post_list or page_list %}
    <p>The site has some blog post or pages</p>
{% endif %}

If anyone of the two variables is true then <p>The site has some blog post or pages</p> will be printed. Otherwise, nothing would be printed.

Here are some more examples:

1
2
3
{% if not post_list or author_list %}
    <p>There are no posts or there are some authors</p>
{% endif %}

Here the not operator only negates the post_list variable. So the string <p>There are no posts or there are some authors</p> will only get printed when either there are no posts (i.e post_list empty) or there are some authors (author_list is not empty).

You can also use and and or operator within the same tag. The important thing to remember is that the precedence of and is higher than that of or operator. For example:

1
2
3
{% if post_list and page_list or author_list %}
    <p>The site has either both posts and pages or only author</p>
{% endif %}

This code will be interpreted like:

1
2
3
{% if (post_list and page_list) or author_list %}
    <p>The site has either both posts and pages or only author</p>
{% endif %}

However, I want to clarify is that, don't be tempted to use parentheses to group conditions. It is invalid syntax and would throw TemplateSyntaxError exception.

You can also nest one {% if %} tag inside another {% if %} tag. For example:

1
2
3
4
5
{% if num < 10 %}
    {% if num > 5 %}
        <p>The num is greater than 5 but less than 10</p>
    {% endif %}    
{% endif %}

Using Relational Operators #

You can also use relational operators >, <, >=, <=, != , == with the template tags.

> operator #

1
2
3
{% if num > 10 %}
    <p>The num is greater than 10</p>
{% endif %}

If num is greater than 10, then <p>The num is greater than 10</p> will be printed.

< operator #

1
2
3
{% if num < 10 %}
    <p>The num is lesser than 10</p>
{% endif %}

If num is smaller than 10, then <p>The num is lesser than 10</p> will be printed.

>= operator #

1
2
3
{% if num >= 10 %}
    <p>The num is greater than or equal to 10</p>
{% endif %}

If num is greater than or equal to 10, then <p>The num is greater than or equal to 10</p> will be printed.

<= operator #

1
2
3
{% if num <= 10 %}
    <p>The num is lesser than or equal to 10</p>
{% endif %}

If num is smaller than or equal to 10, then <p>The num is lesser than or equal to 10</p> will be printed.

== operator #

1
2
3
{% if num == 10 %}
    <p>The num is equal to 10</p>
{% endif %}

If num is equal to 10, then <p>The num is equal to 10</p> will be printed.

!= operator #

1
2
3
{% if num != 10 %}
    <p>The num is not equal to 10</p>
{% endif %}

If num is not equal to 10, then <p>The num is not equal to 10</p> will be printed.

in, not in and is operator #

in operator #

1
2
3
{% if 10 in num_list %}
    <p>Yes, the number 10 is in the num_list</p>
{% endif %}

If the number 10 exists in the num_list, then <p>Yes, the number 10 is in the num_list</p> will be printed.

not in operator #

1
2
3
{% if 10 not in list %}
    <p>Yes, the number 10 is not in the list</p>
{% endif %}

If the number 10 doesn't exist in the num_list, then <p>Yes, the number 10 is in the num_list</p> will be printed.

is operator #

Just as in Python code, the is operator in templates is used to compare two objects. If two objects are same then the is operator returns True. Otherwise False.

1
2
3
{% if obj is user %}
    <p>Yes obj is same as user</p>
{% endif %}

Here, if object pointed to by variable obj is same as that of variable user then the text <p>Yes obj is same as user</p> will be printed.

for tag #

A {% for %} tag allows us to use to loop through a sequence (or collection). We can use {% for %} tag to iterate over the contents of list, tuples, dictionary etc. Here is the syntax of the {% for %} tag:

1
2
3
{% for i in my_list %}
    <p>The value of i is {{ i }}</p>
{% endfor %}

Here is how it works:

When the loop begins the first value from the list my_list is assigned to the variable i. Then the template engine will render everything between {% for %} and {% endfor %}. This process keeps repeating until there are no more elements left to iterate in the list.

To print a list in the reverse order add reversed keyword after the list as follows.

1
2
3
{% for i in my_list reversed %}
    <p>The value of i is {{ i }}</p>
{% endfor %}

Sometimes in your Django journey, you have to work with list of list. To access the list of list unpack elements of sublist into individual variables. For example, let's say we have the following list in our context.

list = [ ["uno", "one"], ["dos", "two"], ["tres", "three"], ["cuatro", "four"] ]

To loop over a list of list inside the template do this:

1
2
3
{% for x, y in list %}
    <p>{{ x }} : {{ y }}</p>
{% endfor %}

The output will be:

1
2
3
4
uno : one
dos : two
tres : three
cuatro : four

Similarly, we can access elements of a dictionary. Let's say our context variable contains a dictionary named dict.

dict = { 'uno': 'one', 'dos': 'two', 'tres': 'three', 'cuatro': 'four' }

To access this dictionary inside the template use the following code:

1
2
3
{% for k, v in dict.items %}
    <p>{{ k }} : {{ v }}</p>
{% endfor %}

The output will be something like this:

1
2
3
4
cuatro : four
uno : one
tres : three
dos : two

Note that the elements in a dictionary are stored in no particular order. So the above output may differ.

for empty tag #

Suppose we have a variable called post_list which contains a list of post objects. Our job is to print a list of all blog posts. We can do so, using a for tag as follows:

1
2
3
{% for post in post_list %}
    <h2>{{ post.title }}</h2>
{% endfor %}

There is one problem though; we haven't checked whether any blog posts exists or not. Here is the updated code:

1
2
3
4
5
6
7
{% if post_list %}
    {% for post in post_list %}
        <h2>{{ post.title }}</h2>
    {% endfor %}
{% else %}
    No post published yet.
{% endif %}

This kind of pattern is so common that Django provides a nice shortcut to it. The for tag can take an additional {% empty %} tag. This tag let you define what to output in the case if the list is empty. For example:

1
2
3
4
5
{% for post in post_list %}
    <h2>{{ post.title }}</h2>
{% empty %}
    No post published yet.        
{% endfor %}

Just like nested if tags we can have nested for tags.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{% for post in post_list %}
    <p>{{ post.content }}</p>
    <p>
        <ul>
            {% for tag in post.tags %}
            <li>{{ tag }}</li>
            {% endfor %}            
        </ul>
    </p>
{% endfor %}

The for tag provides a special variable called forloop. The forloop has several attributes which can be used to track the progress of the loop.

forloop.counter - It returns a number indicating the current iteration of the loop. It starts with 1. For example, let's say our context contains a list named list defined as follows:

list = [11,12,13]
1
2
3
{% for i in list %}
    <p>{{ forloop.counter }} Iteration - {{ i }}</p>
{% endfor %}

Then the above for loop will print the following output:

1
2
3
1 Iteration - 11
2 Iteration - 12
3 Iteration - 13

forloop.counter0 - Works same as forloop.counter but begins with 0 instead of 1.

1
2
3
{% for i in list %}
    <p>{{ forloop.counter0 }} Iteration - {{ i }}</p>
{% endfor %}

Output:

1
2
3
0 Iteration - 11
1 Iteration - 12
2 Iteration - 13

forloop.revcounter - It returns the number of iteration from the end of the loop.

1
2
3
{% for i in list %}
    <p>{{ forloop.revcounter }} Iteration - {{ i }}</p>
{% endfor %}

Output:

1
2
3
3 Iteration - 11
2 Iteration - 12
1 Iteration - 13

forloop.revcounter0 - Same as forloop.revcounter but it is 0 indexed.

1
2
3
{% for i in list %}
    <p>{{ forloop.revcounter0 }} Iteration - {{ i }}</p>
{% endfor %}

Output:

1
2
3
2 Iteration - 11
1 Iteration - 12
0 Iteration - 13

forloop.first - It returns a boolean True if the current iteration is the first iteration. Otherwise False.

1
2
3
{% for i in list %}
    <p>{{ forloop.first }} Iteration - {{ i }}</p>
{% endfor %}

Output:

1
2
3
True Iteration - 11
False Iteration - 12
False Iteration - 13

forloop.last - It returns a boolean True if the current iteration is the last iteration. Otherwise False.

1
2
3
{% for i in list %}
    <p>{{ forloop.last }} Iteration - {{ i }}</p>
{% endfor %}

Output:

1
2
3
False Iteration - 11
False Iteration - 12
True Iteration - 13

forloop.parentloop - It is used in the nested for loop to refer to the forloop variable in the parent for loop. For example:

1
2
3
4
5
6
7
8
9
{% for i in list %}
    <table>
    {% for j in i %}
        <tr>
            <td>{{ forloop.parentloop.counter }} - {{ forloop.counter }} - {{ i }}</td>
        </tr>
    {% endfor %}
    </table>
{% endfor %}

url tag #

The url tag is used to generate URLs inside the template. It has the following syntax:

{% url 'url_name' arg1 arg2 %}

where url_name is the name of the URL pattern. The arg1 and arg2 refers to arguments required by the URL. If URL doesn't accept any arguments just pass the name of the URL pattern. On success, it returns the part of the URL without the host portion. If it can't create the URL NoReverseMatch exception is thrown.

In case you have namespaced URLs, specify fully qualified name just as we did while calling the reverse() function in chapter Creating URLs and Custom Response:

{% url 'my_app:url_name' arg1 arg2 %}

Here are some examples:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
>>> 
>>> from django import template
>>>
>>> t = template.Template("{% url 'djangobin:time' %}") 
>>> t.render(template.Context())
'/time/'
>>> 
>>> 
>>> t = template.Template("{% url 'djangobin:index' %}")
>>> t.render(template.Context())
'/'
>>> 
>>> 
>>> t = template.Template("{% url 'djangobin:profile' 'foobar' %}")
>>> t.render(template.Context())
'/user/foobar/'
>>> 
>>> 
>>> t = template.Template("{% url 'djangobin:book_category' 'crime' %}")
>>> t.render(template.Context())
'/book/crime/'
>>> 
>>>
>>> t = template.Template("{% url 'djangobin:contact' %}")
>>> t.render(template.Context())
Traceback (most recent call last):
    ...
django.urls.exceptions.NoReverseMatch: Reverse for 'contact' not found. 'contact' is not a valid view function or pattern name. 
>>>