
Templates
Learn how to create dynamic HTML pages using Django's template system.
What are Templates?
Templates are HTML files with special Django syntax that allow you to: - Display dynamic data - Use template inheritance - Include reusable components - Apply filters and tags
Template Location
Create templates in your app:
myapp/
templates/
myapp/
index.html
post_detail.html
Django looks for templates in:
1. app/templates/app/ (app-specific)
2. templates/ (project-wide)
Basic Template
Simple Template
<!-- myapp/templates/myapp/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>My Blog</title>
</head>
<body>
<h1>Welcome to My Blog</h1>
<p>This is the home page.</p>
</body>
</html>
Rendering Template
# myapp/views.py
from django.shortcuts import render
def index(request):
return render(request, 'myapp/index.html')
Template Variables
Display data from views:
In View
def index(request):
context = {
'title': 'Home Page',
'name': 'John',
'age': 30,
}
return render(request, 'myapp/index.html', context)
In Template
<h1>{{ title }}</h1>
<p>Hello, {{ name }}! You are {{ age }} years old.</p>
Accessing Object Attributes
# View
def post_detail(request, post_id):
post = get_object_or_404(Post, id=post_id)
return render(request, 'myapp/post_detail.html', {'post': post})
<!-- Template -->
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<p>Published: {{ post.created_at }}</p>
Template Tags
Special syntax for logic in templates:
for Loop
<ul>
{% for post in posts %}
<li>{{ post.title }}</li>
{% endfor %}
</ul>
if Statement
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}!</p>
{% else %}
<p>Please log in.</p>
{% endif %}
if-else
{% if post.status == 'published' %}
<p>This post is published.</p>
{% else %}
<p>This post is a draft.</p>
{% endif %}
Empty for Loop
{% for post in posts %}
<p>{{ post.title }}</p>
{% empty %}
<p>No posts available.</p>
{% endfor %}
Template Filters
Modify variable output:
Common Filters
<!-- Uppercase -->
{{ name|upper }}
<!-- Lowercase -->
{{ name|lower }}
<!-- Title case -->
{{ title|title }}
<!-- Length -->
{{ posts|length }}
<!-- Date formatting -->
{{ post.created_at|date:"F d, Y" }}
<!-- Truncate text -->
{{ post.content|truncatewords:30 }}
<!-- Default value -->
{{ name|default:"Guest" }}
<!-- Safe (render HTML) -->
{{ content|safe }}
Chaining Filters
{{ name|upper|truncatewords:5 }}
Template Inheritance
Reuse common HTML structure:
Base Template
<!-- myapp/templates/myapp/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Blog{% endblock %}</title>
<style>
/* Common styles */
</style>
</head>
<body>
<header>
<h1>My Blog</h1>
<nav>
<a href="/">Home</a>
<a href="/about/">About</a>
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 My Blog</p>
</footer>
</body>
</html>
Child Template
<!-- myapp/templates/myapp/index.html -->
{% extends 'myapp/base.html' %}
{% block title %}Home - My Blog{% endblock %}
{% block content %}
<h2>Latest Posts</h2>
{% for post in posts %}
<article>
<h3>{{ post.title }}</h3>
<p>{{ post.get_excerpt }}</p>
<a href="{% url 'post_detail' post.id %}">Read more</a>
</article>
{% endfor %}
{% endblock %}
Including Templates
Reuse template components:
Component Template
<!-- myapp/templates/myapp/post_card.html -->
<div class="post-card">
<h3>{{ post.title }}</h3>
<p>{{ post.get_excerpt }}</p>
<small>{{ post.created_at|date:"M d, Y" }}</small>
</div>
Include in Main Template
{% for post in posts %}
{% include 'myapp/post_card.html' %}
{% endfor %}
URL Tag
Generate URLs in templates:
<!-- Using URL name -->
<a href="{% url 'post_detail' post.id %}">Read more</a>
<!-- With namespace -->
<a href="{% url 'blog:post_detail' post.id %}">Read more</a>
<!-- With multiple arguments -->
<a href="{% url 'post_archive' year=2024 month=1 %}">Archive</a>
Static Files
Include CSS, JavaScript, and images:
Settings
# settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [BASE_DIR / 'static']
In Template
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
<script src="{% static 'js/main.js' %}"></script>
<img src="{% static 'images/logo.png' %}" alt="Logo">
Complete Example
Base Template
<!-- myapp/templates/myapp/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Blog{% endblock %}</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header>
<nav>
<a href="{% url 'post_list' %}">Home</a>
<a href="{% url 'about' %}">About</a>
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 My Blog</p>
</footer>
</body>
</html>
Post List Template
<!-- myapp/templates/myapp/post_list.html -->
{% extends 'myapp/base.html' %}
{% block title %}Posts - My Blog{% endblock %}
{% block content %}
<h1>Latest Posts</h1>
{% if posts %}
<div class="post-list">
{% for post in posts %}
<article class="post-card">
<h2><a href="{% url 'post_detail' post.id %}">{{ post.title }}</a></h2>
<p class="meta">
Published: {{ post.created_at|date:"F d, Y" }}
by {{ post.author.username }}
</p>
<p>{{ post.get_excerpt }}</p>
<a href="{% url 'post_detail' post.id %}">Read more →</a>
</article>
{% endfor %}
</div>
{% else %}
<p>No posts available.</p>
{% endif %}
{% endblock %}
Post Detail Template
<!-- myapp/templates/myapp/post_detail.html -->
{% extends 'myapp/base.html' %}
{% block title %}{{ post.title }} - My Blog{% endblock %}
{% block content %}
<article>
<h1>{{ post.title }}</h1>
<p class="meta">
Published: {{ post.created_at|date:"F d, Y" }}
by {{ post.author.username }}
</p>
<div class="content">
{{ post.content|linebreaks }}
</div>
<a href="{% url 'post_list' %}">← Back to posts</a>
</article>
{% endblock %}
Template Context Processors
Add data to all templates automatically:
# settings.py
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
This makes request and user available in all templates.
Best Practices
- Use template inheritance: Avoid repeating HTML
- Keep logic in views: Templates should display, not process
- Use includes: For reusable components
- Organize templates: Group by app
- Use URL names: Makes URLs maintainable
- Load static files: Use
{% load static %}
Common Mistakes
1. Not Extending Base Template
<!-- ❌ Wrong - repeating HTML -->
<!DOCTYPE html>
<html>
<head>...</head>
<body>...</body>
</html>
<!-- ✅ Correct -->
{% extends 'myapp/base.html' %}
{% block content %}...{% endblock %}
2. Forgetting to Load Static
<!-- ❌ Wrong -->
<link rel="stylesheet" href="/static/css/style.css">
<!-- ✅ Correct -->
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
3. Logic in Templates
<!-- ❌ Wrong - complex logic in template -->
{% for post in posts %}
{% if post.status == 'published' and post.created_at > yesterday %}
...
{% endif %}
{% endfor %}
<!-- ✅ Correct - filter in view -->
# In view:
posts = Post.objects.filter(status='published', created_at__gte=yesterday)
Practice Exercise
Create templates for:
- Base template with header, navigation, and footer
- Home page listing all posts
- Post detail page showing full post
- About page
- Use template inheritance
- Include static CSS file
- Use URL tags for navigation
What's Next?
Now that you understand templates, learn to:
- Handle Forms - Process user input
- User Authentication - Login, logout, registration
- Admin Interface - Customize Django admin
- Deploy Your App - Put your site online
Previous Tutorial: Views and URLs
Next Tutorial: Forms