📝 Html Css

Django: Template Tags

P
Author
Pyland
📅
Published
30.06.2026
⏱️
Reading time
2 min
👁️
Views
87
🌿
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

📝

pytest-django: Testing Django

Охватываемые темы: Installation, @pytest.mark.djangodb, Fixtures, Testing views.

📅 30.06.2026 👁️ 138
📝

Colors and Fonts in CSS

The first thing a DevBlog reader sees is text. Well-chosen colors and fonts make a...

📅 30.06.2026 👁️ 81
📝

CSS Selectors

A selector is the first part of a CSS rule. It tells the browser: "apply...

📅 30.06.2026 👁️ 84

Did you like the article?

Subscribe to our updates and receive new articles first. Grow with PyLand!