Server-side rendering with Django templates and HTMX focuses on generating dynamic HTML on the server while enhancing interactivity on the client side.
Django templates handle rendering content using server data, and HTMX allows parts of a page to be updated dynamically through HTTP requests without relying heavily on JavaScript. This approach simplifies development while delivering fast and responsive user experiences.
What is Server-Side Rendering?
Server-side rendering generates complete HTML on the server before sending it to the browser, unlike client-side rendering where JavaScript builds the page after load.
This approach ensures content is immediately visible and indexable by search engines from the first request.
Django Templates Fundamentals
Django templates provide a clean, Pythonic way to generate dynamic HTML with minimal boilerplate.
They use a template inheritance system that promotes reusable, DRY (Don't Repeat Yourself) code structures.
Key Django Template Features
1. Template inheritance: Extends base layouts like {% extends 'base.html' %}
2. Template tags: Control flow with {% if %}, {% for %}, {% block %}
3. Filters: Transform data like {{ name|title }} or {{ items|length }}
4. Context processors: Automatic access to user, request, and settings data
Here's a basic Django template structure:
<!-- base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
<nav>{% block nav %}{% endblock %}</nav>
<main>{% block content %}{% endblock %}</main>
</body>
</html><!-- child.html -->
{% extends 'base.html' %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h1>Welcome, {{ user.name }}!</h1>
{% endblock %}Why HTMX Complements Django Perfectly
HTMX extends HTML with attributes that trigger AJAX requests, making dynamic UIs simple without writing JavaScript.
It works seamlessly with Django because both embrace the philosophy of HTML as the primary interface.
HTMX Core Attributes:
HTMX extends HTML with attributes that trigger AJAX requests, making dynamic UIs simple without writing JavaScript.
It works seamlessly with Django because both embrace the philosophy of HTML as the primary interface.
HTMX Core Attributes
Setting Up Your Django + HTMX Project
Let's build a real-world task management app to see these concepts in action.
Follow these steps to create a dynamic, server-rendered application.
1. Project Setup and Dependencies
Create Django project:
django-admin startproject taskapp
cd taskapp
python manage.py startapp tasksInstall HTMX (via CDN or download):
<script src="https://unpkg.com/htmx.org@1.9.10"></script>Update settings.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'tasks', # Your app
]2. Building the Task Model and Views
models.py (Create a simple Task model):
from django.db import models
from django.contrib.auth.models import User
class Task(models.Model):
PRIORITY_CHOICES = [
('low', 'Low'),
('medium', 'Medium'),
('high', 'High'),
]
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
priority = models.CharField(max_length=10, choices=PRIORITY_CHOICES, default='medium')
completed = models.BooleanField(default=False)
created_by = models.ForeignKey(User, on_delete=models.CASCADE)
created_at = models.DateTimeField(auto_now_add=True)views.py (Mixed full-page and HTMX views):
from django.shortcuts import render, get_object_or_404
from django.http import JsonResponse
from django.views.decorators.http import require_http_methods
from .models import Task
def task_list(request):
"""Full page render for initial load"""
tasks = Task.objects.filter(created_by=request.user)
return render(request, 'tasks/list.html', {'tasks': tasks})
@require_http_methods(["POST"])
def create_task(request):
"""HTMX partial render for AJAX form submission"""
# Create task logic here
task = Task.objects.create(
title=request.POST['title'],
created_by=request.user
)
# Return HTML fragment only
return render(request, 'tasks/partials/task_item.html', {'task': task})3. Creating Interactive Templates
templates/tasks/list.html (Main page with HTMX):
{% extends 'base.html' %}
{% block content %}
<div class="container">
<h1>My Tasks</h1>
<!-- Add Task Form (HTMX-powered) -->
<form hx-post="/tasks/create/"
hx-target="#task-list"
hx-swap="beforeend"
class="mb-4 p-4 border rounded">
<input type="text" name="title" placeholder="New task..."
class="form-control mb-2" required>
<button type="submit" class="btn btn-primary">Add Task</button>
</form>
<!-- Dynamic task list -->
<ul id="task-list" class="list-group">
{% for task in tasks %}
{% include 'tasks/partials/task_item.html' with task=task %}
{% endfor %}
</ul>
</div>
{% endblock %}templates/tasks/partials/task_item.html (Reusable partial):
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<h5 class="task-title {% if task.completed %}text-muted{% endif %}">
{{ task.title }}
</h5>
<small class="text-muted">{{ task.created_at|date:"M d, Y" }}</small>
</div>
<!-- Toggle completion with HTMX -->
<button hx-post="/tasks/{{ task.id }}/toggle/"
hx-target="closest li"
hx-swap="outerHTML"
class="btn {% if task.completed %}btn-success{% else %}btn-outline-success{% endif %}">
{% if task.completed %}✓ Done{% else %}Mark Done{% endif %}
</button>
</li>Advanced HTMX Patterns with Django
Once comfortable with basics, explore these powerful patterns professionals use daily.
Progressive Enhancement Strategy
Build pages that work without JavaScript, then enhance with HTMX.
Implementation Pattern
1. Create fully-functional forms using standard POST
2. Add hx-post, hx-target attributes for enhancement
3. Server returns same HTML fragments for both
4. Graceful degradation if JavaScript disabled
Real-Time Features with WebSockets
Combine HTMX with Django Channels for live updates
<!-- Live notifications -->
<div hx-get="/notifications/poll/"
hx-trigger="every 5s"
hx-target="#notifications"
hx-swap="innerHTML">
</div>Performance and Best Practices
Maximize your Django + HTMX applications with these proven techniques.
Optimization Checklist
1. Use partial templates for HTMX responses (avoid full page layouts)
2. Implement caching with Django's @cache_page decorator
3. Minimize payload - return only changed HTML fragments
4. Add loading states with hx-indicator
5. Handle errors gracefully with hx-on::after-request
6. Use CSRF tokens properly in HTMX forms
Example: Loading States
<div id="results" hx-get="/search/" hx-trigger="keyup delay:300ms"
hx-indicator="#loading">
Search results will appear here...
</div>
<div id="loading" class="htmx-indicator">
<em>Loading...</em>
</div>Security Best Practices:
1. Always validate/sanitize form data on server
2. Use {% csrf_token %} in HTMX forms
3. Implement permission checks in views
4. Rate-limit AJAX endpoints
5. Escape user-generated content with Django's template filters