USD ($)
$
United States Dollar
Euro Member Countries
India Rupee

Server-side Rendering with Django Templates and HTMX

Lesson 16/27 | Study Time: 15 Min

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:

text
<!-- 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>


text
<!-- 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:

bash
django-admin startproject taskapp
cd taskapp
python manage.py startapp tasks


Install HTMX (via CDN or download):

xml
<script src="https://unpkg.com/htmx.org@1.9.10"></script>


Update settings.py:

python
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):

python
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):

python
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):

xml
{% 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):

xml
<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

xml
<!-- 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

xml
<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


himanshu singh

himanshu singh

Product Designer
Profile