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 .