~/TechPurAI
~/tutorials/django-from-scratch/templates-and-rendering
beginner·part 4 of 22·2 min read

Rendering templates: connecting a view to HTML

Updated Aug 31, 2026Python · Django

HttpResponse("some string") was enough to prove the routing works — real pages need actual HTML. This part is deliberately brief on template syntax; the standalone Django template views tutorial is the full reference for {% %} tags, filters, and inheritance in depth. Here, it's just wired into the blog project.

The app's templates folder

text
blog/
    templates/
        blog/
            base.html
            post_list.html

Django looks for templates inside a templates/ folder on each installed app's own path — the blog/ folder nested inside templates/ is a namespacing convention (covered fully in the standalone tutorial), and skipping it is what causes two apps that both have a post_list.html to silently collide.

A base layout

django
{# blog/templates/blog/base.html #}
<!DOCTYPE html>
<html>
<head><title>{% block title %}My Blog{% endblock %}</title></head>
<body>
  <header><h1><a href="/">My Blog</a></h1></header>
  <main>{% block content %}{% endblock %}</main>
</body>
</html>

Every template this series adds from here on extends this one file — the header, the <!DOCTYPE>, the overall shell only ever gets written once.

Rendering the post list

python
# blog/views.py
from django.shortcuts import render

def post_list(request):
    return render(request, "blog/post_list.html")
django
{# blog/templates/blog/post_list.html #}
{% extends "blog/base.html" %}

{% block title %}Latest posts{% endblock %}

{% block content %}
  <p>Posts will render here once there's a Post model to query.</p>
{% endblock %}

render() replaces the raw HttpResponse from part 3 — it loads the template, renders it, and wraps the result in a response, in one call. Refresh http://127.0.0.1:8000/ and the base layout now renders around the placeholder text.

FAQ

How does Django find blog/post_list.html from just that string in render()? It searches every installed app's templates/ folder for a matching path, in the order apps are listed in INSTALLED_APPS — the blog/ prefix inside the templates folder (part of this page's namespacing convention) is what's being matched, not a literal filesystem path relative to the project root.

Can I pass data into a template from the view? Yes — render(request, "blog/post_list.html", {"posts": some_queryset}) is the pattern; the dict's keys become variables usable inside the template with {{ posts }}. This part skips it only because there's no Post model to query yet — the very next part adds one.

Where do CSS and images go, since there's no mention of them here? Static files (CSS, JavaScript, images) use a separate system from templates — a static/ folder per app plus Django's {% load static %} template tag — deliberately out of scope for this part, which is focused on the render pipeline itself.

Next: an actual Post model, so this page has real data to loop over instead of placeholder text.

VK

Vijay Kumar

Founder of TechPurAI — writing hands-on tutorials and honest tool breakdowns.

LinkedIn ↗
← previous3. URLs and views: routing a request to a responsenext →5. Models and the ORM: defining your data