Get AI summaries of any video or article — Sign up free
Python Django Tutorial: Full-Featured Web App Part 3 - Templates thumbnail

Python Django Tutorial: Full-Featured Web App Part 3 - Templates

Corey Schafer·
4 min read

Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Create blog/templates/blog/ and place home.html and about.html inside the app-named subfolder so Django can locate them.

Briefing

Django templates turn repetitive, full-page HTML strings in view functions into reusable HTML files—then let those pages receive dynamic data and share a single layout. The practical payoff is immediate: home and about pages stop being hard-coded responses and instead render complete HTML documents from template files, with Django handling the final HTTP response.

The workflow starts by creating a templates directory inside the Django app. Django looks for templates under a app-level templates folder, so the tutorial builds blog/templates/blog/ and places home.html and about.html there. After that, the blog app is added to settings.py via its app configuration (blog.apps.<BlogConfigName>), ensuring Django searches the correct templates location. Views then switch from returning HttpResponse with headings to returning render(request, template_name, context). For home, the template name is blog/home.html; for about, it’s blog/about.html. Once render is wired up, the browser shows the full HTML structure from the templates, not just a fragment.

The next step is passing data into templates. Dummy post data is created in views as a list of dictionaries (author, title, content, date_posted). That list is placed into a context dictionary under the key post, and context is passed as the third argument to render. Inside home.html, Django’s template language loops over the posts using a for block (for post in posts) and prints fields with double curly braces like {{ post.title }}, {{ post.author }}, {{ post.date_posted }}, and {{ post.content }}. The tutorial also demonstrates conditional rendering: templates can check whether a title variable exists and fall back to a default like “Django blog” using an if/else block.

To eliminate duplicated markup between pages, the tutorial introduces template inheritance. A base.html template holds the shared structure—head elements, navigation scaffolding, and a single block named content. Home.html and about.html then use {% extends 'blog/base.html' %} and override only the content block with page-specific HTML. This design choice becomes more than aesthetic: when Bootstrap is added to base.html (via copied starter template CSS/JS and a container wrapper), every inheriting page automatically gains the updated styling. The tutorial further adds global CSS through Django static files (blog/static/blog/main.css), inserts reusable HTML snippets for articles, and updates the navigation bar to use Django’s {% url %} tag instead of hard-coded href paths.

By the end, templates are no longer just static HTML files. They become a maintainable system: views feed data via context, templates render it with loops and conditionals, base templates centralize shared layout, static assets style everything consistently, and URL tags keep navigation correct even if route patterns change later.

Cornell Notes

Django templates replace view functions that return raw HTML with reusable HTML files stored under app/templates/app/. Views render those files using render(request, template_name, context). Context data can be passed into templates as dictionaries, then accessed with double curly braces (e.g., {{ post.title }}). Templates support control flow with {% for %} loops and {% if %} conditionals, enabling dynamic lists like blog posts. To avoid repeating shared markup across pages, template inheritance uses a base template (base.html) with a named block (content) that child templates override. Centralizing layout in base.html makes global changes—like adding Bootstrap, navigation, and CSS—apply across all pages automatically.

How does Django know where to find templates for a specific app?

Templates are stored in a templates directory inside the app. The tutorial creates blog/templates/blog/ and places home.html and about.html inside the inner blog folder. Django then searches that app-specific templates location when the app is included in settings.py via its app configuration (blog.apps.<BlogConfigName>).

What does render() do compared with returning HttpResponse directly?

render(request, template_name, context) returns an HTTP response after loading the specified template and injecting any context variables. Instead of manually building HTML strings in views, the view returns the rendered template (e.g., blog/home.html or blog/about.html), and Django handles the final HTML output.

How are dynamic values like post titles displayed inside templates?

Views pass data into templates through a context dictionary. In the tutorial, dummy posts are a list of dictionaries with keys like title, author, content, and date_posted. In the template, values are printed using double curly braces such as {{ post.title }} and {{ post.content }}.

How do templates display a list of posts?

A {% for %} loop iterates over the posts passed in context. The tutorial uses a loop like {% for post in posts %} ... {% endfor %}, then renders each post’s fields inside the loop. Because there are two dictionaries in the dummy list, the template outputs two post sections.

How does template inheritance reduce duplication between home and about pages?

A base.html template contains shared HTML (head, navigation, and a content block). Child templates use {% extends 'blog/base.html' %} and override the block with page-specific content using {% block content %} ... {% endblock content %}. This means changes to shared layout (like Bootstrap CSS/JS) happen in one place and apply to all inheriting pages.

Why switch navigation links from hard-coded href values to the {% url %} tag?

Hard-coded paths require updating templates whenever URL patterns change. The tutorial replaces href values with {% url 'blog-home' %} and {% url 'blog-about' %}, using the route names defined in blog/urls.py. This keeps links correct even if the underlying paths change later. Login/register links remain placeholders until those routes exist.

Review Questions

  1. Where should the templates directory be located for Django to find app-specific templates, and what folder naming convention is used?
  2. How do context variables become accessible inside templates, and what syntax prints them?
  3. What are the roles of base.html, {% extends %}, and {% block %} in template inheritance?

Key Points

  1. 1

    Create blog/templates/blog/ and place home.html and about.html inside the app-named subfolder so Django can locate them.

  2. 2

    Add the blog app configuration to settings.py (installed apps) so Django searches the correct templates directory.

  3. 3

    Use render(request, template_name, context) in views to return fully rendered HTML instead of building strings with HttpResponse.

  4. 4

    Pass dynamic data by supplying a context dictionary to render, then access values in templates with {{ variable }}.

  5. 5

    Use {% for %} loops to iterate over lists of dictionaries and {% if %}/{% else %} blocks for conditional rendering.

  6. 6

    Eliminate duplicated page structure with template inheritance: put shared layout in base.html and override a named block like content in child templates.

  7. 7

    Keep navigation maintainable by using {% url %} with named URL patterns rather than hard-coded href paths.

Highlights

Django’s render() lets views return complete HTML pages from template files, with context injected automatically.
Template loops and conditionals (for/if) make it possible to render repeated post sections and default titles without duplicating markup.
Template inheritance centralizes shared layout in base.html, so adding Bootstrap or global CSS once updates every page that extends it.
Using {% url %} in templates prevents broken navigation when URL routes change later.
Static assets (like blog/main.css) are loaded via {% load static %} and the static tag, keeping styling organized per app.

Topics