Django Templates: Best Practices
Tags: django, python, webdev, beginners
Published: 2019-10-15 19:10:50

---
title: Django Templates: Best Practices
published: true
description: In practice, Django’s templates are simply HTML files, with some special syntax and a set of tools which lets Django render the HTML page on-the-fly for the visiting user.
tags: django, python, webdev, beginners
cover_image: https://thepracticaldev.s3.amazonaws.com/i/u3upnt2opt4jikzh70i7.png
series: Django Tutorials on Kite's Blog
canonical_url: https://kite.com/blog/python/django-templates-best-practices/
---

## Introduction to Django templates

Django, as a web framework, uses templates as a way of producing static HTML from the output of a Django view. In practice, Django’s templates are simply HTML files, with some special syntax and a set of tools which lets Django render the HTML page on-the-fly for the visiting user. Templates are highly customizable, but are meant to be simple, with most of the “heavy” logic going into the view. Let’s dive deeper and learn some standard ways of dealing with common problems.

## Simple start with Django templates

By default, Django comes with a ton of built-in template *tags* and *filters* that help us perform repeatable template tasks throughout our apps. 

**Tags:** Tags provide arbitrary logic in the rendering process. Django leaves this definition fairly vague, but tags are able to output content, grab content from the database (more on this later), or perform control operations like if statements or for loops.

Examples of tags*:*

```django
{% firstof user.is_active user.is_staff user.is_deleted %}
```

The [`firstof`](https://kite.com/python/docs/django.template.defaulttags.firstof) tag will output the first provided variable which evaluates to `True`. This is a good replacement for a large `if/elif/elif/elif/elif` block that’s just evaluating on truthiness within your Django templates.

```django
<ul>
{% for product in product_list %}
    <li>{{ product.name }}: ${{ product.price }}</li>
{% endfor %}
</ul>
```

The `for` tag in Django will loop over each item in a list, making that item (*product*, in this case) available in the template context before the tag is closed with `endfor`. This is a widely used pattern when working with lists of Django model instances which have been returned from the view.

**Filters:** Filters transform the values of variables and arguments. Filters would be used in tasks like rendering a string in uppercase or formatting a date string into a user’s region.

Examples of filters*:*

```django
{{ value|date:'D d M Y' }}
```

The [**date**](https://kite.com/python/docs/django.template.defaultfilters.date) filter will format a date (`value`, in the example) given a string with some format characters. The example would output the string: `Mon 01 Apr 2019`.

```django
{{ value|slugify }}
```

The [**slugify**](https://kite.com/python/docs/django.template.defaultfilters.slugify) filter will convert the spaces of a string into hyphens and convert the string to lowercase, among other things. The output of this example `would-look-something-like-this`.

## Project structure

Django, by default, will make some assumptions about the structure of our project when it’s looking for templates. Knowing this, we can set up our project with a *template directory* and *application template directories*. 

Imagine a project, cloud*,* with the following structure:

```bash
cloud/
	accounts/
		urls.py
		models.py
		views.py
		templates/
			accounts/
				login.html
				register.html
	blog/
		urls.py
		views.py
		models.py
		templates/
			blog/
				create.html
				post.html
				list.html
	config/
		settings/
			base.py
			local.py
		urls.py
	manage.py
	templates/
		includes/
			messages.html
			modal.html
		base.html
		logged_in.html
```

## How inheritance works for Django templates

An important aspect of Django’s templating system is *template inheritance*. Django applications are meant to be reusable, and we can apply the same methodology to our templates by inheriting common HTML from other templates.

A typical pattern is to have a common base template for common aspects of your application, logged-in pages, logged-out pages, or in places where significant changes are made to the underlying HTML. From our example above, `base.html `would contain most of the core structure that would make up each page, with *blocks* defined for app or page-specific customizations. 

For example, `base.html` may contain:

```django
{% load static %}
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  {% block page_meta %}
  {% endblock %}

  {# Vendor styles #}
  {% block vendor_css %}
    <link rel="stylesheet" type="text/css" media="all" href="{% static 'css/vendor.css' %}" />
  {% endblock %}

  {# Global styles #}
  {% block site_css %}
    <link rel="stylesheet" type="text/css" media="all" href="{% static 'css/application.css' %}" />
  {% endblock %}

  {# Page-specific styles #}
  {% autoescape off %}
    {% block page_css %}{% endblock %}
  {% endautoescape %}

  {% block extra_head %}
    {# Extra header stuff (scripts, styles, metadata, etc) #}
  {% endblock %}

  <title>{% block page_title %}{% endblock %}</title>
</head>
<body class="{% block body_class %}{% endblock %}">
{% block body %}
    {# Page content will go here #}
{% endblock %}

{# Modal HTML #}
{% block modals %}
{% endblock %}

{# Vendor javascript #}
{% block vendor_js %}
  <script src="{% static 'js/vendor.js' %}"></script>
{% endblock %}

{# Global javascript #}
{% block site_js %}
  <script src="{% static 'js/application.js' %}"></script>
{% endblock %}

{# Shared data for javascript #}
<script type="text/javascript">
  window._sharedData = {
    {% autoescape off %}
      {% block shared_data %}
        'DEBUG': {% if debug %}true{% else %}false{% endif %},
      {% endblock %}
    {% endautoescape %}
  }
</script>

{# Page javascript #}
{% autoescape off %}
  {% block page_js %}
  {% endblock %}
{% endautoescape %}
</body>
</html>
```

There are a few things done in this example specifically for the sake of inheritance. Most notably, this base template has blocks defined for nearly every customizable aspect of the underlying HTML. Blocks for including CSS, JavaScript, an HTML title, meta tags, and more are all defined.

We use Django’s `autoescape` template tag surrounding blocks where we don’t want Django to autoescape our HTML tags or JavaScript, but rather treat the contents of the block literally.

Our `shared_data` block allows us to populate a global JavaScript object with variables and data which we may want to share between Django and any running JavaScript on the page (populating React or Vue.js components, for example.)

For example, if we wanted to pass a Django URL to one of our JavaScript files, we could do something like this:

```django
{% extends 'base.html' %}

{% block shared_data %}
  {{ block.super }}
  'USERS_AUTOCOMPLETE_ENDPOINT': '{% url 'api:users:autocomplete' %}',
{% endblock %}
```

Django loads the page and returns in a JavaScript object that you can then use within the JavaScript files on the page:

```django
<script type="text/javascript">
    window._sharedData = {      
    	'DEBUG': false,
    	'USERS_AUTOCOMPLETE_ENDPOINT': '/api/users/autocomplete/',
    }
</script>
```

The inside of a JS console once the page has loaded:

```bash
>> window._sharedData.DEBUG
false
>> window._sharedData.USERS_AUTOCOMPLETE_ENDPOINT
'/api/users/autocomplete/'
```

## Handling querysets

Properly handling querysets within your templates can be a performance bottleneck for Django depending on the complexities of your model definitions. 

Django’s templating system is tightly coupled with Django’s object-relational mapping layer which returns us data from the database. Without proper consideration of this coupling you may, inadvertently, cause the number of queries run on each page load to jump to unmaintainable amounts. In some cases, this can cause the database to become too sluggish to operate certain pages on your site, or worse, crash and need to be restarted.

Thankfully, Django provides mechanisms and patterns which we can use to make sure our templates are running as fast as possible and we’re not killing the database server. 

Consider this common Django pattern:

accounts/views.py
```python
class UserListView(ListView):
    template_name = 'accounts/list.html'
    model = User
    paginate_by = 25
    context_object_name = 'users'
    queryset = User.objects.all()
```

accounts/templates/accounts/list.html
```django
...
<table>
  <thead>
  <tr>
    <th>Username</th>
    <th>Email</th>
    <th>Profile photo URL</th>
    <th>Joined</th>
  </tr>
  </thead>
  <tbody>
  {% for user in users %}
    <tr>
      <td>{{ user.username }}</td>
      <td>{{ user.email_address }}</td>
      <td>{{ user.profile.avatar_url }}</td>
      <td>{{ user.created_at }}</td>
    </tr>
  {% endfor %}
  </tbody>
</table>
...
```

Can you spot the problem? It may not be obvious at first, but look at this line:

```django
<td>{{ user.profile.avatar_url }}</td>
```

When Django is processing and rendering our template (line by line), it will need to do an additional query to grab information from the *profile* object as it’s a related field. In our example view, we’re paginating by 25 users, so this one line in the template could account for an additional 25 queries (on each page request as the profile object, as with all related objects and models in Django) which aren’t included in the original query for the 25 users. You can imagine how this could become a very slow page if we were including fields from other related objects in our table, or if we were paginating by 100 users instead of 25.

To resolve this, we’ll change one line in our view, `accounts/views.py`, to [**select related**](https://kite.com/python/docs/django.db.models.query.QuerySet.select_related) objects when we’re running our original query for users:

```python
class UserListView(ListView):
    template_name = 'accounts/list.html'
    model = User
    paginate_by = 25
    context_object_name = 'users'
    queryset = User.objects.select_related('profile')
```

By replacing our `User.objects.all()` with `User.objects.select_related(‘profile’)`, we’re telling Django to include related profile instances when it’s performing its query for our users. This will include the `Profile` model on each `User` instance, preventing Django from needing to run an extra query each time we ask for information from the profile within the template.

Django’s `select_related` functionality does not work with many-to-many model relationships, or with many-to-one relationships. For this, we’d want to use Django’s [`prefetch_related`](https://docs.djangoproject.com/en/2.1/ref/models/querysets/#prefetch-related) method.

Unlike `select_related`, `prefetch_related` does its magic in Python, as opposed to SQL select statements, by joining related objects into instances which can be accessed in templates as we’ve done above. It doesn’t perform things in a single query like `select_related` is able to, but it’s much more efficient than running a query each time you request a related attribute.

A prefetch for related **projects** and **organizations** and one-to-many relationships off of the `User` model would look like this:

... check out the [full article and source code](https://kite.com/blog/python/django-templates-best-practices/) from kite.com!

*Zac Clancy is Vice President at Global DIRT (Disaster Immediate Response Team)*