๐Ÿ“ Html Css

Django: Template Tags

P
Author
PyLand Team
๐Ÿ“…
Published
30.06.2026
โฑ๏ธ
Reading time
2 min
๐Ÿ‘๏ธ
Views
304
๐ŸŒฟ
Level
Medium

Template tags are logic inside HTML. Unlike {{ variable }} which only outputs a value, {% %} tags control flow: branches, loops, URLs, block composition.

{% if %} โ€” conditional output

{% if user.is_authenticated %}
  <a href="{% url 'logout' %}">Log out</a>
{% elif user.is_staff %}
  <a href="/admin/">Admin panel</a>
{% else %}
  <a href="{% url 'login' %}">Log in</a>
{% endif %}

Supported operators: ==, !=, <, >, and, or, not, in.

{% if posts and not page_obj.has_next %}
  <p>This is the last page.</p>
{% endif %}

{% if post.status == "published" %}
  <span class="badge bg-success">Published</span>
{% endif %}

{% for %} โ€” iterating over lists

{% for post in posts %}
  <article>
    <h2>{{ post.title }}</h2>
    <p>{{ post.summary }}</p>
  </article>
{% empty %}
  <p>No articles yet.</p>
{% endfor %}

{% empty %} runs when the list is empty โ€” equivalent to if not posts.

Variables inside a loop

Django provides a forloop object automatically:

{% for post in posts %}
  <div class="{% if forloop.first %}mt-0{% else %}mt-4{% endif %}">
    {{ forloop.counter }}. {{ post.title }}
    {% if forloop.last %}<hr>{% endif %}
  </div>
{% endfor %}
Variable Value
forloop.counter Iteration number (starting at 1)
forloop.counter0 Iteration number (starting at 0)
forloop.first True on the first iteration
forloop.last True on the last iteration

Don’t hardcode paths โ€” use URL names:

<!-- urls.py: path('posts/<slug:slug>/', PostDetailView.as_view(), name='post-detail') -->

<a href="{% url 'post-detail' slug=post.slug %}">{{ post.title }}</a>
<a href="{% url 'post-list' %}">All articles</a>
<a href="{% url 'admin:index' %}">Administration</a>

If you rename a URL in urls.py, all links update automatically.

{% csrf_token %} โ€” form protection

Every form with method POST must include this tag:

<form method="post" action="{% url 'comment-create' post.pk %}">
  {% csrf_token %}
  <textarea name="text"></textarea>
  <button type="submit">Submit</button>
</form>

Without {% csrf_token %} Django returns a 403 error. The tag inserts a hidden field with a unique session token.

{% load static %} โ€” loading static files

{% load static %}

<link rel="stylesheet" href="{% static 'css/main.css' %}">
<script src="{% static 'js/main.js' %}"></script>
<img src="{% static 'images/logo.png' %}" alt="Logo">

{% load static %} must appear once at the top of the file (or after {% extends %}). Details are in the static files article.

{% block %} and {% extends %} โ€” template inheritance

A base template defines placeholder blocks:

{# base.html #}
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}DevBlog{% endblock %}</title>
</head>
<body>
  {% block content %}{% endblock %}
</body>
</html>

A child template inherits and fills in the blocks:

{% extends 'base.html' %}

{% block title %}{{ post.title }} โ€” DevBlog{% endblock %}

{% block content %}
  <h1>{{ post.title }}</h1>
  <div>{{ post.body }}</div>
{% endblock %}

Details are in the template inheritance article.

Full Example: DevBlog Post List Template

{% extends 'base.html' %}
{% load static %}

{% block title %}Articles โ€” DevBlog{% endblock %}

{% block content %}
<div class="container py-4">
  <h1>All Articles</h1>

  {% if posts %}
    <div class="row g-4">
      {% for post in posts %}
        <div class="col-12 col-md-6 col-lg-4">
          <div class="card h-100">
            <div class="card-body">
              <h5 class="card-title">
                <a href="{% url 'post-detail' slug=post.slug %}">
                  {{ post.title }}
                </a>
              </h5>
              <p class="card-text text-muted">{{ post.summary }}</p>
            </div>
            <div class="card-footer text-muted small">
              {{ post.published_at }}
            </div>
          </div>
        </div>
      {% endfor %}
    </div>
  {% else %}
    <div class="alert alert-info">
      No articles yet. Check back later!
    </div>
  {% endif %}

</div>
{% endblock %}

Your reaction to the article

๐Ÿ’ฌ Comments (0)

๐Ÿ” Sign in to leave a comment
๐Ÿšช Login
๐Ÿ’ญ

No comments yet

Be the first to share your opinion about this article!

๐Ÿ”— Similar

Similar articles

Continue learning with these materials

๐Ÿ“

Django: Static Files

Static files are CSS, JavaScript, images, and fonts. Django handles them in a specific way:...

๐Ÿ“… 30.06.2026 ๐Ÿ‘๏ธ 289
๐Ÿ“

Django: Template Inheritance

Without inheritance, every HTML template would contain duplicated code: navigation, CSS/JS links, footer. Inheritance lets...

๐Ÿ“… 30.06.2026 ๐Ÿ‘๏ธ 318
๐Ÿ“

Django: Forms in Templates

A Django form is a Python class. In a template it becomes HTML. Let's look...

๐Ÿ“… 30.06.2026 ๐Ÿ‘๏ธ 292
๐ŸŽ“ Continue learning

Courses that cover this material

Visit the course to apply this material in practice.

Markup for Backend Developers Open course curriculum