Skip to content

Django Templates and Static Files

Django templates help you show dynamic data in HTML. This chapter explains templates, static files, app setup, and Tailwind in simple steps. By the end, you will know how to create reusable templates, serve static files, and use Tailwind for styling in your Django projects.

Django ships with its own template engine called Django Template Language (DTL). DTL syntax is similar to Jinja2, so many examples look alike, but DTL is the default and recommended engine for standard Django projects.

Keep using DTL for most Django tutorials and simple sites. If you prefer Jinja2, Django supports it as an alternative backend.

By default Django searches for templates in a templates/ folder inside each app (when APP_DIRS=True) and in directories you list under TEMPLATES[0]["DIRS"] in settings.py.

Add a project-level templates directory like this:

TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"], # project-level templates
"APP_DIRS": True, # include app-level templates
"OPTIONS": {
# context processors, etc.
},
},
]

Use double curly braces to output variables and {% %} for template tags.

Hello {{ name }}!

If the view passes name = "Kumar Shail", the rendered output will be Hello Kumar Shail!.

{% if name %}
Hello, {{ name }}!
{% endif %}
{% for item in items %}
{{ item }}
{% endfor %}

block / endblock: define overridable sections in a base template.

Section titled “block / endblock: define overridable sections in a base template.”
<title>{% block title %}My Website{% endblock title %}</title>
{% extends "base.html" %}

include: insert another template file (useful for headers/footers).

Section titled “include: insert another template file (useful for headers/footers).”
{% include "partials/header.html" %}

load static / static: use these to reference static assets (CSS, JS, images).

Section titled “load static / static: use these to reference static assets (CSS, JS, images).”
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<a href="{% url 'all_items' %}">All Items</a>

Template inheritance keeps common layout in one file and lets child templates override only the sections they need.

templates/base.html (example):

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<title>{% block title %}My Project{% endblock title %}</title>
</head>
<body>
<nav><!-- common navbar --></nav>
<main>{% block content %}{% endblock content %}</main>
<footer><!-- common footer --></footer>
</body>
</html>

Child template (core/templates/core/all_items.html):

{% extends "base.html" %}
{% block title %}All Items{% endblock title %}
{% block content %}
<h1>All Items</h1>
<p>Welcome {{ name }}</p>
{% for item in names %}
<p>{{ item }}</p>
{% endfor %}
{% endblock content %}

Render templates from a view using django.shortcuts.render.

core/views.py:

from django.shortcuts import render
def all_items(request):
context = {
"name": "Kumar Shail",
"names": ["Tea", "Coffee", "Juice"],
}
return render(request, "core/all_items.html", context)

core/urls.py:

from django.urls import path
from . import views
urlpatterns = [
path("", views.all_items, name="all_items"),
]

Include the app URLs in the project urls.py:

from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("items/", include("core.urls")),
]

Visit http://localhost:8000/items/ to see the page.

For static pages without dynamic context, use TemplateView.

app/urls.py:

from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path("", TemplateView.as_view(template_name="core/index.html"), name="index"),
]

Static files are files served directly to the client: CSS, JavaScript, images, fonts, etc. During development, runserver serves static files when DEBUG=True. In production, use a dedicated static file server or a middleware like WhiteNoise.

Install WhiteNoise (or use your package manager):

Terminal window
uv add whitenoise

Add WhiteNoise to MIDDLEWARE in settings.py (after SecurityMiddleware):

MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
# other middleware...
]
STATIC_URL = "/static/"
STATICFILES_DIRS = [BASE_DIR / "static"]
STATIC_ROOT = BASE_DIR / "staticfiles"
STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage"

Create a sample stylesheet at core/static/core/css/style.css or static/css/style.css:

body {
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial;
padding: 1rem;
}

Collect static files for production with manage.py collectstatic and serve STATIC_ROOT from your web server or use WhiteNoise.

This project uses django-tailwind for a convenient Tailwind workflow inside Django. The commands below assume the helper uv is available in your environment; otherwise install packages with pip and run management commands with python manage.py.

Install the required packages:

Terminal window
uv add django-tailwind django-browser-reload

Add the Tailwind and theme apps to INSTALLED_APPS in settings.py:

INSTALLED_APPS = [
# other apps...
"tailwind",
"theme", # the Tailwind theme app created by tailwind init
]
# development-only tools
if ENVIRONMENT != PRODUCTION:
INSTALLED_APPS += ["django_browser_reload"]
TAILWIND_APP_NAME = "theme"
INTERNAL_IPS = ["127.0.0.1", "localhost"]
NPM_BIN_PATH = "npm" if os.name != "nt" else r"C:\Program Files\nodejs\npm.cmd"

Add django_browser_reload middleware in development:

if ENVIRONMENT != PRODUCTION:
MIDDLEWARE += ["django_browser_reload.middleware.BrowserReloadMiddleware"]

Add the reload URL when in development:

from django.conf import settings
from django.urls import include, path
urlpatterns = [
path("admin/", admin.site.urls),
path("items/", include("core.urls")),
]
if settings.ENVIRONMENT != settings.PRODUCTION:
urlpatterns += [path("__reload__/,", include("django_browser_reload.urls"))]

Initialize and install the Tailwind toolchain (run in your project root):

Terminal window
uv run python manage.py tailwind init
uv run python manage.py tailwind install

Use Tailwind in templates (example base.html):

{% load static %}
{% load static tailwind_tags %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
{% tailwind_css %}
<title>{% block title %}My Project{% endblock title %}</title>
</head>
<body class="bg-slate-100 text-slate-900">
{% block content %}{% endblock content %}
</body>
</html>

During development run two processes:

Terminal window
uv run python manage.py runserver
Terminal window
uv run python manage.py tailwind start

To build Tailwind assets for production:

Terminal window
uv run python manage.py tailwind build