Introduction
Django templates use Jinja2 syntax with Django-specific extensions. Templates enable dynamic HTML generation with inheritance, filters, and template tags.
Template Configuration
# settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.jinja2.Jinja2',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'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',
],
'extensions': [
'jinja2.ext.i18n',
],
},
},
]
# Use Django templates instead
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR / 'templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [...],
},
},
]
Template Inheritance
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
{% block extra_css %}{% endblock %}
</head>
<body>
<nav>
<a href="{% url 'home' %}">Home</a>
<a href="{% url 'about' %}">About</a>
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer>
{% block footer %}© 2024{% endblock %}
</footer>
{% block extra_js %}{% endblock %}
</body>
</html>
<!-- templates/blog/post_list.html -->
{% extends 'base.html' %}
{% block title %}Blog - {{ block.super }}{% endblock %}
{% block content %}
<h1>Blog Posts</h1>
{% for post in posts %}
<article>
<h2>{{ post.title }}</h2>
<p>{{ post.content|truncatewords:50 }}</p>
<a href="{% url 'post_detail' post.slug %}">Read more</a>
</article>
{% empty %}
<p>No posts available.</p>
{% endfor %}
{% if is_paginated %}
{% include 'pagination.html' %}
{% endif %}
{% endblock %}
Custom Filters
# app/templatetags/custom_filters.py
from django import template
register = template.Library()
@register.filter
def truncate_words(value, arg):
"""Truncate value to arg number of words."""
words = value.split()
if len(words) > arg:
return ' '.join(words[:arg]) + '...'
return value
@register.filter
def currency(value):
"""Format value as currency."""
return f'${value:,.2f}'
@register.simple_tag
def get_greeting(name):
"""Return a greeting message."""
return f'Hello, {name}!'
@register.inclusion_tag('weather.html')
def show_weather(location):
"""Include weather template with context."""
weather_data = get_weather_data(location)
return {'weather': weather_data}
Template Tags
# app/templatetags/form_tags.py
from django import template
register = template.Library()
@register.simple_tag
def url_replace(request, field, value):
"""Replace query parameter in URL."""
dict_ = request.GET.copy()
dict_[field] = value
return dict_.urlencode()
@register.inclusion_tag('blog/post_list.html')
def recent_posts(count=5):
"""Show recent blog posts."""
from blog.models import Post
posts = Post.objects.filter(status='published')[:count]
return {'posts': posts}
Practice Problems
- Create a base template with navigation, main content area, and footer
- Implement a custom filter that formats dates in a specific locale
- Build a template tag that displays related posts based on tags
- Create a multi-level inheritance structure (base, base_blog, post_detail)
- Implement a template tag that handles pagination URL generation