Django & Flask Topic

Django Templates and the Django Template Language (DTL)

Django follows the MVT (Model-View-Template) pattern. While the View (Python logic) fetches and prepares data, the Template is responsible for how that data looks.

  • Templates are mostly HTML files with special placeholders and logic tags.

  • DTL (Django Template Language) is the syntax you use inside these HTML files to create dynamic content.

This separation is crucial: designers can work on templates without touching Python code, and developers can focus on logic without messing with HTML.


1. What are Django Templates?

A Django template is a text file that defines the structure or layout of a file (like an HTML page), with placeholders for actual content.

  • It uses a combination of static HTML and dynamic DTL tags/variables.

  • By convention, they live in a templates directory inside your app.

Template Configuration

For Django to find your templates, ensure your app is in INSTALLED_APPS (in settings.py) and you have a structure like this:

text

myproject/
    myapp/
        templates/
            myapp/
                base.html
                index.html
                post_detail.html

The inner myapp directory prevents name collisions if multiple apps have templates with the same name.


2. Key Concepts in Action

Let's continue with our blog example and see how to display the data we queried using the ORM.

Template Inheritance: {% extends %} and {% block %}

This is the most powerful part of DTL. It lets you define a base "skeleton" template that other templates can build upon. This avoids repeating the same HTML structure (like navigation, headers, footers) on every page.

1. The Base Template (base.html)

This template defines the overall structure and "blocks" where child templates can insert their content.

html

<!-- myapp/templates/myapp/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}My Awesome Blog{% endblock %}</title>
    <!-- Bootstrap CSS or your own styles -->
</head>
<body>
    <header>
        <h1><a href="/">My Awesome Blog</a></h1>
        <nav><!-- ... navigation links ... --></nav>
    </header>

    <main>
        {% block content %}
        <!-- This is a placeholder. Content from child templates goes here. -->
        {% endblock %}
    </main>

    <footer>
        <p>&copy; 2023 My Blog</p>
    </footer>
</body>
</html>

2. A Child Template (index.html)

This template extends the base template and fills the blocks with its own specific content.

html

<!-- myapp/templates/myapp/index.html -->
{% extends "myapp/base.html" %}

<!-- Override the 'title' block -->
{% block title %}Homepage - My Awesome Blog{% endblock %}

<!-- Override the 'content' block -->
{% block content %}
    <h2>Latest Blog Posts</h2>
    
    {% for post in posts %}
        <article>
            <h3>{{ post.title }}</h3>
            <p>By <strong>{{ post.author.name }}</strong> on {{ post.published_date|date:"F j, Y" }}</p>
            <p>{{ post.content|truncatewords:30 }}</p>
            <a href="#">Read more...</a>
        </article>
    {% empty %}
        <p>No posts yet!</p>
    {% endfor %}

{% endblock %}

How it works:

  • {% extends "myapp/base.html" %} tells Django this template is a child of base.html.

  • {% block content %}...{% endblock %} defines the content that will be placed inside the corresponding {% block content %} placeholder in the base template.

  • The final rendered page is a combination of base.html and the filled-in blocks from index.html.

Using Variables: {{ variable }}

Variables are how you output data passed from your view. You surround them with double curly braces.

In your view (Python logic):

python

from django.shortcuts import render
from .models import BlogPost

def index(request):
    posts = BlogPost.objects.all().order_by('-published_date')[:5] # Get 5 latest posts
    context = {
        'posts': posts, # Make the 'posts' queryset available to the template
        'site_name': "My Cool Blog"
    }
    return render(request, 'myapp/index.html', context)

In your template (HTML/DTL):

html

<h1>Welcome to {{ site_name }}!</h1>
<!-- This will output: "Welcome to My Cool Blog!" -->

<article>
    <h3>{{ post.title }}</h3> <!-- Outputs the post's title -->
    <p>By {{ post.author.name }}</p> <!-- You can access attributes with a dot -->
</article>

Using Tags: {% for %}, {% if %}

Tags are more complex logic. They are surrounded by {% ... %} and can perform loops, conditionals, and more.

  • The {% for %} tag:

    html

    {% for post in posts %}
        <li>{{ forloop.counter }}. {{ post.title }}</li>
    {% empty %}
        <!-- This block is shown if the 'posts' list is empty -->
        <li>Sorry, no posts available.</li>
    {% endfor %}
    • forloop.counter is a special variable that gives the current iteration (1-indexed).

  • The {% if %} tag:

    html

    {% if user.is_authenticated %}
        <p>Welcome back, {{ user.username }}! <a href="/logout/">Logout</a></p>
    {% else %}
        <p>Please <a href="/login/">log in</a>.</p>
    {% endif %}
    
    <!-- You can use filters in conditionals too -->
    {% if post.categories.count > 0 %}
        <p>This post is in {{ post.categories.count }} categories.</p>
    {% endif %}

     

Using Filters

Filters transform variable output. They are used with a pipe character |.

  • Syntax: {{ variable|filter_name:argument }}

  • Examples:

    html

    <!-- Text Manipulation -->
    <h2>{{ post.title|upper }}</h2> <!-- Makes title UPPERCASE -->
    <p>{{ post.content|truncatewords:30 }}</p> <!-- Shows only first 30 words -->
    
    <!-- Date Formatting -->
    <p>Published: {{ post.published_date|date:"F j, Y" }}</p> <!-- Outputs: "October 25, 2023" -->
    <p>Published: {{ post.published_date|timesince }} ago</p> <!-- Outputs: "3 days ago" -->
    
    <!-- Handling empty values -->
    <p>Subtitle: {{ post.subtitle|default:"No subtitle provided." }}</p>
    
    <!-- Pluralization -->
    <p>{{ post.categories.count }} categor{{ post.categories.count|pluralize:"y,ies" }}</p>
    <!-- If count is 1: "1 category" -->
    <!-- If count is 5: "5 categories" -->

     

Summary

Concept Syntax Purpose Example
Variable {{ ... }} Output a value. {{ post.title }}
Tag {% ... %} Execute logic (loops, conditionals). {% for ... %}, {% if ... %}
Filter {{ var|filter }} Transform a variable's output. {{ content|truncatewords:30 }}
Extends {% extends "" %} Inherit from a base/parent template. {% extends "base.html" %}
Block {% block %}...{% endblock %} Define a replaceable section in a template. {% block content %}...{% endblock %}

The Workflow:

  1. View fetches data from the Model using the ORM.

  2. View passes that data (as a "context" dictionary) to a Template.

  3. The Template uses DTL (variables, tags, filters) and inheritance to render the final, dynamic HTML page.

  4. The View sends this rendered HTML back to the user's browser.

Comments (0)

No comments yet. Be the first to comment!

LecturreAI Assistant

Hello! I'm LecturreAI

What would you like to learn today?