Django templates cheatsheet.

Variables

{{ user.name }}
{{ user.posts.count }}
{{ user.get_full_name }}        # callable, no parens
{{ posts.0.title }}              # index

Filters

{{ name|upper }}
{{ name|lower }}
{{ name|capfirst }}
{{ name|title }}
{{ name|default:"Anonymous" }}
{{ name|default_if_none:"(empty)" }}
{{ html|safe }}
{{ html|escape }}
{{ html|striptags }}
{{ text|truncatechars:100 }}
{{ text|truncatewords:20 }}
{{ text|linebreaks }}
{{ text|linebreaksbr }}

{{ date|date:"Y-m-d" }}
{{ date|date:"F j, Y" }}
{{ date|time:"H:i" }}
{{ date|timesince }}
{{ date|naturaltime }}             # humanize

{{ items|length }}
{{ items|first }}
{{ items|last }}
{{ items|join:", " }}
{{ items|slice:":5" }}
{{ items|dictsort:"name" }}

{{ n|add:1 }}
{{ price|floatformat:2 }}
{{ size|filesizeformat }}

{{ url|urlencode }}
{{ q|urlize }}

Tags

{% if user.is_authenticated %}...{% else %}...{% endif %}
{% if x and y %}...{% endif %}
{% if x in items %}...{% endif %}

{% for post in posts %}
  {{ forloop.counter }}: {{ post.title }}
  {{ forloop.first }} / {{ forloop.last }}
{% empty %}
  No posts
{% endfor %}

{% url 'blog:detail' id=post.id %}
{% csrf_token %}
{% now "Y-m-d H:i" %}

{% block content %}{% endblock %}
{% extends "base.html" %}
{% include "partials/header.html" %}
{% include "partials/card.html" with post=post %}

Template inheritance

<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}MyApp{% endblock %}</title>
</head>
<body>
  <header>{% include "partials/nav.html" %}</header>
  <main>{% block content %}{% endblock %}</main>
  <footer>{% block footer %}© 2026{% endblock %}</footer>
</body>
</html>
<!-- page.html -->
{% extends "base.html" %}

{% block title %}Posts — {{ block.super }}{% endblock %}

{% block content %}
<h1>Posts</h1>
{% endblock %}

with / as

{% with total=order.total %}
  Total: ${{ total }}
{% endwith %}

{% url 'blog:list' as list_url %}
<a href="{{ list_url }}">List</a>

Static files

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

Custom template tag (simple)

# blog/templatetags/__init__.py (empty)
# blog/templatetags/blog_tags.py

from django import template

register = template.Library()

@register.simple_tag
def greet(name):
    return f"Hello, {name}!"

@register.filter
def to_dollars(cents):
    return f"${cents / 100:.2f}"
{% load blog_tags %}

{% greet "World" %}
{{ price|to_dollars }}

Inclusion tag

@register.inclusion_tag("blog/_user_card.html")
def user_card(user):
    return {"user": user, "is_active": user.is_active}
{% load blog_tags %}
{% user_card user %}

Context processors

# blog/context_processors.py
def site(request):
    return {"site_name": "MyApp", "year": 2026}
# settings.py
TEMPLATES = [{
    "BACKEND": "...",
    "OPTIONS": {
        "context_processors": [
            ...,
            "blog.context_processors.site",
        ],
    },
}]

Now {{ site_name }} available in every template.

Conditional CSS classes

<li class="{% if post.featured %}featured{% endif %} item">

htmx + templates

<form hx-post="{% url 'add' %}" hx-target="#list" hx-swap="beforeend">
  {% csrf_token %}
  <input name="text" required>
  <button>Add</button>
</form>

<ul id="list">
  {% for item in items %}
    {% include "_item.html" %}
  {% endfor %}
</ul>
def add(request):
    item = Item.objects.create(text=request.POST["text"])
    return render(request, "_item.html", {"item": item})

Auto-escaping

{{ user_input }}         <!-- auto-escaped -->
{{ html_content|safe }}  <!-- raw HTML (be sure it's safe!) -->

{% autoescape off %}
  {{ raw_html }}
{% endautoescape %}

Lookups: getattr-like

{{ user.name }}      # tries: user["name"], user.name, user.name(), user[0] (for int)

Comments

{# single line #}

{% comment %}
multi-line
comment
{% endcomment %}

Performance: cached template loader

TEMPLATES = [{
    "OPTIONS": {
        "loaders": [(
            "django.template.loaders.cached.Loader",
            ["django.template.loaders.filesystem.Loader", "django.template.loaders.app_directories.Loader"],
        )],
    },
}]

Cache parsed templates. Important for prod.

Jinja2 (alternative)

TEMPLATES = [{
    "BACKEND": "django.template.backends.jinja2.Jinja2",
    ...
}]

Faster, friendlier syntax for some. Loses Django-specific tags.

Common mistakes

  • {% if x = 1 %} → wrong; use {% if x == 1 %} (no =).
  • Calling method with parens: {{ user.full_name() }} — Django auto-calls.
  • Forgetting {% load static %} / {% load blog_tags %}.
  • HTML auto-escape blocked unintentionally with |safe.
  • Heavy queries in template (loops triggering DB) — refactor to view.

Read this next

If you want my template snippets + base templates, they’re at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .