This page looks best with JavaScript enabled

Django DTL(Django Template Language)

 ·  🎃 kr0m

Django templates allow us to render the HTML code that will be sent to the client’s browser. Through DTL, we can structure the web page by showing the data received from the views in the way that suits us best. Additionally, DTL allows us to extend and include other templates, so we can reuse code between templates.

Before starting, it is recommended to read the previous articles on Django as they are the previous steps to this article:


Through the admin App, we have inserted several exercises and a routine to continue developing the code and perform real tests. This time we will show the routines using a very simple template in which we will use a for loop to iterate them.

Activate the project’s venv:

cd rxWod
source bin/activate
cd rxWodProject/

Create the templates directory in the rxWod app:

mkdir -p rxWod/templates/rxWod

Create the template that will iterate the routines:

vi rxWod/templates/rxWod/index.html

{% if routines %}
    <ul>
    {% for routine in routines %}
        <li><a>{{ routine.date }}</a></li>
    {% endfor %}
    </ul>
{% else %}
    <p>No routines available.</p>
{% endif %}

Modify the index view to query the routines from the database and send them to the template via context:

vi rxWod/views.py

from django.shortcuts import render
from django.http import HttpResponse
from .models import Routine

def index(request):
    routines = Routine.objects.order_by('id')
    context = {
        'routines': routines,
    }
    return render(request, 'rxWod/index.html', context)

The flow is as follows:

URL -> View -> Code Execution -> Context -> Rendered through template -> Response*

The template rendering shows the following content:

In templates, we should avoid hardcoding paths. In this example, we show a hardcoded form action:

<form action="/show_routine" method="post">
{% csrf_token %}
    <input name="routine_id" value={{ routine.id }} type="hidden"></input>
    <button type="submit" class="btn-link">{{ routine.date }}</button>
</form>

On the other hand, we can indicate it in the following way using NameSpaces. This method has the advantage that when we make changes to the URLs, they will automatically be reflected in our templates.

<form action="{% url 'rxWod:show_routine' %}" method="post">
{% csrf_token %}
    <input name="routine_id" value={{ routine.id }} type="hidden"></input>
    <button type="submit" class="btn-link">{{ routine.date }}</button>
</form>

A good way to organize the code in templates is through includes. A very simple example can be the following:

vi rxWod/templates/rxWod/minimal.html

<!doctype html>
<html lang="en">
    <head>
        <!-- Required meta tags for BootStrap -->
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <title>rxWod</title>
        {% block minimal_head %}
        {% endblock %}
    </head>
    <body>
        <p>Minimal Template</p>
        {% block minimal_body %}
        {% endblock %}
    </body>
</html>
vi rxWod/templates/rxWod/base.html
{% extends 'rxWod/minimal.html' %}

{% block minimal_head %}
    {% block base_head %}
    {% endblock %}
{% endblock %}

{% block minimal_body %}
    <p>Base template</p>
    {% block base_body %}
    {% endblock %}
{% endblock %}
vi rxWod/templates/rxWod/index.html
{% extends 'rxWod/base.html' %}

{% block base_body %}
        {% if routines %}
            <ul>
            {% for routine in routines %}
                <li><a>{{ routine.date }}</a></li>
            {% endfor %}
            </ul>
        {% else %}
            <p>No routines available.</p>
        {% endif %}
{% endblock %}

If we access the index, we can see the content of each include:

Now that we know how to use views and templates, the rest of the app is simply programming the remaining functionalities.

If you liked the article, you can treat me to a RedBull here