Templates & Static Files
Learn to work with Django templates, static files, and the template language for building dynamic web pages. This is a foundational concept in Python web development that professional developers rely on daily. The explanations below are written to be beginner-friendly while covering the depth and nuance that comes from real-world Python/Django experience. Take your time with each section and practice the examples
Django Templates
Django templates are HTML files that can contain Django template language syntax for dynamic content rendering.. This is an essential concept that every Python/Django developer must understand thoroughly. In professional development environments, getting this right can mean the difference between code that works reliably and code that breaks in production. The following sections break this down into clear, digestible pieces with practical examples you can try immediately
Template Structure and Syntax
<!-- base.html - Base template -->
<!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 Django Site{% endblock %}</title>
{% load static %}
<link rel="stylesheet" href="{% static 'css/style.css' %}">
</head>
<body>
<header>
<nav>
<ul>
<li><a href="{% url 'home' %}">Home</a></li>
<li><a href="{% url 'blog:post_list' %}">Blog</a></li>
<li><a href="{% url 'about' %}">About</a></li>
<li><a href="{% url 'contact' %}">Contact</a></li>
</ul>
</nav>
</header>
<main>
{% block content %}
{% endblock %}
</main>
<footer>
<p>© 2024 My Django Site. All rights reserved.</p>
</footer>
<script src="{% static 'js/main.js' %}"></script>
</body>
</html>
<!-- post_list.html - Extends base template -->
{% extends 'base.html' %}
{% load static %}
{% block title %}Blog Posts{% endblock %}
{% block content %}
<div class="container">
<h1>Blog Posts</h1>
{% if posts %}
<div class="posts-grid">
{% for post in posts %}
<article class="post-card">
<h2><a href="{% url 'blog:post_detail' post.pk %}">{{ post.title }}</a></h2>
<p class="post-meta">
By {{ post.author }} on {{ post.published_date|date:"F j, Y" }}
</p>
<p class="post-excerpt">{{ post.excerpt|truncatewords:30 }}</p>
<div class="post-tags">
{% for tag in post.tags.all %}
<span class="tag">{{ tag.name }}</span>
{% endfor %}
</div>
</article>
{% endfor %}
</div>
{% if is_paginated %}
<div class="pagination">
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">« Previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.num_pages }}
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">Next »</a>
{% endif %}
</div>
{% endif %}
{% else %}
<p>No posts available.</p>
{% endif %}
</div>
{% endblock %}Practice Exercise: Template Tag Library
# Custom template tags for Django
from django import template
from django.utils.safestring import mark_safe
import markdown
from datetime import datetime, timedelta
register = template.Library()
@register.filter(name='markdown')
def markdown_filter(text):
"""Convert markdown text to HTML"""
return mark_safe(markdown.markdown(text))
@register.filter(name='time_ago')
def time_ago_filter(value):
"""Show relative time (e.g., '2 hours ago')"""
if not value:
return ""
now = datetime.now()
if value.tzinfo:
now = now.replace(tzinfo=value.tzinfo)
diff = now - value
if diff.days > 0:
return f"{diff.days} day{'s' if diff.days != 1 else ''} ago"
elif diff.seconds > 3600:
hours = diff.seconds // 3600
return f"{hours} hour{'s' if hours != 1 else ''} ago"
elif diff.seconds > 60:
minutes = diff.seconds // 60
return f"{minutes} minute{'s' if minutes != 1 else ''} ago"
else:
return "Just now"
@register.simple_tag
def get_recent_posts(count=5):
"""Get recent blog posts"""
from blog.models import Post
return Post.objects.filter(status='published').order_by('-published_date')[:count]
@register.inclusion_tag('blog/tags/post_tags.html')
def show_post_tags(post):
"""Display post tags with custom styling"""
return {'tags': post.tags.all()}
# Usage in templates:
# {{ post.content|markdown }}
# {{ post.published_date|time_ago }}
# {% get_recent_posts 3 as recent_posts %}
# {% show_post_tags post %}
# post_tags.html template:
"""
<div class="post-tags">
{% for tag in tags %}
<a href="{% url 'blog:tag_posts' tag.slug %}" class="tag tag-{{ tag.color }}">
{{ tag.name }}
</a>
{% endfor %}
</div>
"""