Easy Tutorial
❮ Django Orm 2 Django Views ❯

Django Templates

In the previous section, we used django.http.HttpResponse() to output "Hello World!". This approach mixes data with the view, which does not align with Django's MVC philosophy.

In this section, we will provide a detailed introduction to the application of Django templates. A template is a text that separates the presentation of a document from its content.


Template Application Example

Continuing from the previous section's project, we will create a templates directory under the HelloWorld directory and establish a tutorialpro.html file. The entire directory structure is as follows:

HelloWorld/
|-- HelloWorld
|   |-- __init__.py
|   |-- __init__.pyc
|   |-- settings.py
|   |-- settings.pyc
|   |-- urls.py
|   |-- urls.pyc
|   |-- views.py
|   |-- views.pyc
|   |-- wsgi.py
|   `-- wsgi.pyc
|-- manage.py
`-- templates
    `-- tutorialpro.html

The tutorialpro.html file code is as follows:

HelloWorld/templates/tutorialpro.html File Code:

<h1>{{ hello }}</h1>

From the template, we know that variables use double curly braces.

Next, we need to inform Django about the template file's path. Modify HelloWorld/settings.py, changing TEMPLATES's DIRS to [os.path.join(BASE_DIR, 'templates')], as shown below:

HelloWorld/HelloWorld/settings.py File Code:

...
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],       # Modified location
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]
...

Now, modify views.py to add a new object for submitting data to the template:

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    context          = {}
    context['hello'] = 'Hello World!'
    return render(request, 'tutorialpro.html', context)

HelloWorld/HelloWorld/urls.py File Code:

from django.urls import path

from . import views

urlpatterns = [
    path('tutorialpro/', views.tutorialpro),
]

Here, we use render instead of the previously used HttpResponse. render also uses a dictionary context as a parameter.

The key hello in the context dictionary corresponds to the variable {{ hello }} in the template.

Re-access http://127.0.0.1:8000/tutorialpro to see the page:

This completes the use of templates to output data, thereby achieving the separation of data from the view.

Next, we will specifically introduce the commonly used syntax rules in templates.


Django Template Tags

Variables

Template Syntax:

view: {"HTML variable name": "view variable name"}

HTML: {{ variable_name }}

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request): 
    views_name = "tutorialpro.org" 
    return render(request, "tutorialpro.html", {"name": views_name})

templates/tutorialpro.html:

<p>{{ name }}</p>

Upon revisiting http://127.0.0.1:8000/tutorialpro, you can see the page:

List

In the tutorialpro.html within templates, elements can be accessed using . index.

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    views_list = ["tutorialpro.org1", "tutorialpro.org2", "tutorialpro.org3"]
    return render(request, "tutorialpro.html", {"views_list": views_list})

HelloWorld/templates/tutorialpro.html File Code:

<p>{{ views_list }}</p>   # Retrieves the entire list
<p>{{ views_list.0 }}</p> # Retrieves the first element of the list

Upon revisiting http://127.0.0.1:8000/tutorialpro, you can see the page:

Dictionary

In the tutorialpro.html within templates, values can be accessed using .key.

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    views_dict = {"name": "tutorialpro.org"}
    return render(request, "tutorialpro.html", {"views_dict": views_dict})

HelloWorld/templates/tutorialpro.html File Code:

<p>{{ views_dict }}</p>
<p>{{ views_dict.name }}</p>

Upon revisiting http://127.0.0.1:8000/tutorialpro, you can see the page:

Filters

{{ variable_name | filter:optional_parameter }}

Template filters can modify variables before they are displayed, using the pipe character, as shown below:

{{ name|lower }}

The {{ name }} variable is processed by the lower filter, converting the text to lowercase.

Filter pipelines can be chained, meaning the output of one filter can be the input of the next:

{{ my_list|first|upper }}

This example takes the first element and converts it to uppercase.

Some filters have parameters. Filter parameters follow the colon and are always enclosed in double quotes. For example:

{{ bio|truncatewords:"30" }}

This will display the first 30 words of the bio variable.

Other filters:

default

The default filter provides a default value for the variable.

If the boolean value of the variable passed by views is false, the specified default value is used.

The following values are considered false:

0  0.0  False  0j  ""  []  ()  set()  {}  None

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    name = 0
    return render(request, "tutorialpro.html", {"name": name})
{{ name|default:"tutorialpro.org666" }}

Re-visit http://127.0.0.1:8000/tutorialpro, and you can see the page:

views_str = "<a href='https://www.tutorialpro.org/'>Click to Redirect</a>"
return render(request, "tutorialpro.html", {"views_str": views_str})

HelloWorld/templates/tutorialpro.html File Code:

{{ views_str|safe }}

When you visit http://127.0.0.1:8000/tutorialpro, you can see the page:

if/else Tag

Basic syntax format is as follows:

{% if condition %}
     ... display
{% endif %}

Or:

{% if condition1 %}
   ... display 1
{% elif condition2 %}
   ... display 2
{% else %}
   ... display 3
{% endif %}

Output based on condition. if/else can be nested.

The {% if %} tag accepts and, or, or not keywords to evaluate multiple variables or negate a variable (not), for example:

{% if athlete_list and coach_list %}
     Both athletes and coaches variables are available.
{% endif %}

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    views_num = 88
    return render(request, "tutorialpro.html", {"num": views_num})

HelloWorld/templates/tutorialpro.html File Code:

{% if num > 90 and num <= 100 %}
Excellent
{% elif num > 60 and num <= 90 %}
Pass
{% else %}
Go play~
{% endif %}

When you visit http://127.0.0.1:8000/tutorialpro, you can see the page:

for Tag

The {% for %} tag allows us to iterate over a sequence.

Similar to Python's for statement, the loop syntax is for X in Y, where Y is the sequence to iterate over and X is the variable used in each specific loop.

The template system will render all content between {% for %} and {% endfor %} during each iteration.

<ul>
{% for athlete in athlete_list %}
    <li>{{ athlete.name }}</li>
{% endfor %}
</ul>

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    views_list = ["tutorialpro.org", "tutorialpro.org1", "tutorialpro.org2", "tutorialpro.org3"]
    return render(request, "tutorialpro.html", {"views_list": views_list})

HelloWorld/templates/tutorialpro.html File Code:

{% for i in views_list %}
{{ i }}
{% endfor %}

When you visit http://127.0.0.1:8000/tutorialpro, you can see the page:

Adding a reversed to the tag reverses the list iteration:

{% for athlete in athlete_list reversed %}
...
{% endfor %}

HelloWorld/templates/tutorialpro.html File Code:

{% for i in views_list reversed %}
{{ i }}
{% endfor %}

When you visit http://127.0.0.1:8000/tutorialpro, you can see the page:

Iterating over a dictionary: You can directly use the dictionary .items method and unpack the variables to get the key and value.

HelloWorld/HelloWorld/views.py File Code:

from django.shortcuts import render

def tutorialpro(request):
    views_dict = {"key1": "value1", "key2": "value2", "key3": "value3"}
    return render(request, "tutorialpro.html", {"views_dict": views_dict})

HelloWorld/templates/tutorialpro.html File Code:

{% for key, value in views_dict.items %}
{{ key }}: {{ value }}
{% endfor %}

When you visit http://127.0.0.1:8000/tutorialpro, you can see the page:


from django.shortcuts import render

def tutorialpro(request): views_dict = {"name":"tutorialpro.org","age":18} return render(request, "tutorialpro.html", {"views_dict": views_dict})



## HelloWorld/templates/tutorialpro.html File Code:


{% for i,j in views_dict.items %} {{ i }}---{{ j }} {% endfor %}



When visiting http://127.0.0.1:8000/tutorialpro, the page will display:
Similar to `{% if %}`, `{% ifequal %}` supports optional `{% else %}` tags: 8

{% ifequal section 'sitenews' %} <h1>Site News</h1> {% else %} <h1>No News Here</h1> {% endifequal %}


### Comment Tags

Django comments use `{# #}`.

{# This is a comment #}


### include Tag

The `{% include %}` tag allows the inclusion of other template content within the template.

The following example includes the `nav.html` template:

{% include "nav.html" %}


---

## csrf_token

`csrf_token` is used in form tags to protect against cross-site request forgery.

If the `{% csrf_token %}` tag is not used, a 403 permission error will occur when redirecting the page using a form.

Using the `{% csrf_token %}` tag ensures that data submission via the form will be successful.

**Explanation:**

First, a request is sent to the server to fetch the login page. At this point, the CSRF middleware automatically generates a hidden input tag with a random string in the value attribute. The user receives the login page along with this hidden input tag.

Then, when the user needs to submit data via a form, the hidden input tag is also submitted to the CSRF middleware. This is because the form includes all input tags when submitting data. When the CSRF middleware receives the data, it checks if the random string matches the one it initially sent to the user. If it does, the data submission is successful; if not, a 403 permission error is returned.

---

## Custom Tags and Filters

1. Create a `templatetags` directory under the application directory (at the same level as the `templates` directory, and the directory name must be `templatetags`).

HelloWorld/ |-- HelloWorld | |-- __init__.py | |-- __init__.pyc | |-- settings.py ... |-- manage.py -- templatetags -- templates


2. Create any Python file in the `templatetags` directory, such as `my_tags.py`.

3. The `my_tags.py` file should contain the following code:

from django import template

register = template.Library() # The name 'register' is fixed and cannot be changed


Modify the `TEMPLATES` option in the `settings.py` file to add the `libraries` configuration:

## settings.py Configuration File

... TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', 'DIRS': [BASE_DIR, "/templates",], 'APP_DIRS': True, 'OPTIONS': { 'context_processors': [ 'django.template.context_processors.debug', 'django.template.context_processors.request', 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], "libraries":{ # Add these three lines of configuration 'my_tags':'templatetags.my_tags' # Add these three lines of configuration
} # Add these three lines of configuration }, }, ] ...


4. Use the decorator `@register.filter` to define a custom filter.

**Note:** The decorator can have a maximum of 2 parameters.

@register.filter def my_filter(v1, v2): return v1 * v2

5. Use the decorator @register.simple_tag to define a custom tag.

@register.simple_tag def my_tag1(v1, v2, v3): return v1 * v2 * v3


6. Before using custom tags and filters, import the Python file at the top of the body in the HTML file.

{% load my_tags %}


7. Use custom filters in HTML.

{{ 11|my_filter:22 }}


8. Use custom tags in HTML.

{% my_tag1 11 22 33 %}


9. Semantic tags

Import mark_safe in the Python file.

from django.utils.safestring import mark_safe


When defining a tag, use the mark_safe method to make the tag semantic, similar to the html() method in jQuery. This has the same effect as the safe filter in the front-end HTML file.

@register.simple_tag def my_html(v1, v2): temp_html = "<input type='text' id='%s' class='%s' />" %(v1, v2) return mark_safe(temp_html)


Use this custom tag in HTML to dynamically create tags on the page.

{% my_html "zzz" "xxx" %}


---

## Configuring Static Files

1. Create a directory named `statics` in the project root.

2. Add the following configuration at the bottom of the `settings` file:

STATIC_URL = '/static/' # Alias STATICFILES_DIRS = [ os.path.join(BASE_DIR, "statics"), ]


3. Create directories named `css`, `js`, `images`, and `plugins` within the `statics` directory to store CSS files, JS files, images, and plugins, respectively.

4. Place the Bootstrap framework in the `plugins` directory.

5. Include Bootstrap in the `<head>` tag of the HTML file.

**Note:** Use the alias `static` from the configuration file in the reference path, not the directory `statics`.

<link rel="stylesheet" href="/static/plugins/bootstrap-3.3.7/dist/css/bootstrap.css">


To use static files in templates, include `{% load static %}`. The following example imports an image from the static directory.

## HelloWorld/HelloWorld/views.py file code:

from django.shortcuts import render

def tutorialpro(request): name = "tutorialpro.org" return render(request, "tutorialpro.html", {"name": name})


## HelloWorld/templates/tutorialpro.html file code:

{% load static %} {{name}}<img decoding="async" src="{% static 'images/tutorialpro-logo.png' %}" alt="tutorialpro-logo">


Upon visiting http://127.0.0.1:8000/tutorialpro, you can see the page:

---

## Template Inheritance

Templates can be reused through inheritance to reduce redundancy.

The header and footer of a webpage are usually consistent, so template inheritance can be used for reuse.

A parent template is used for reusable content, and a child template inherits from the parent template and adds its own content.

### Parent Template

**Tags block...endblock:** Reserved areas in the parent template for the child template to fill in with differentiated content. Different reserved areas must have different names.

{% block name %} Reserved area for the child template, can set default content {% endblock name %}


### Child Template

The child template uses the `extends` tag to inherit from the parent template:

{% extends "parent_template_path" %}


If the child template does not set the content for the reserved areas in the parent template, it will use the default content set in the parent template, or it can be left empty.

Set content for the reserved areas in the parent template:

{% block name %} Content {% endblock name %}


Next, create a `base.html` file in the `templates` directory of the previous project with the following code:

<html> <head> <meta charset="utf-8"> <title>tutorialpro.org(tutorialpro.org)</title> </head> <body> <h1>Hello World!</h1> <p>tutorialpro.org Django test.</p> {% block mainbody %} <p>original</p> {% endblock %} </body> </html>


In the above code, the block tag named `mainbody` is the part that can be replaced by inheritors.

All `{% block %}` tags tell the template engine that child templates can override these parts.

`tutorialpro.html` inherits from `base.html` and replaces specific blocks. The modified code for `tutorialpro.html` is as follows:

{% extends "base.html" %}

{% block mainbody %} <p>Inherits from base.html</p> {% endblock %}


The first line of code indicates that `tutorialpro.html` inherits from `base.html`. It can be seen that the block tag with the same name is used to replace the corresponding block in `base.html`.

Upon revisiting the address http://127.0.0.1:8000/tutorialpro, the output is as follows:
❮ Django Orm 2 Django Views ❯