How To Register Templates In Django

How To Register Templates In Django

It is entirely possible to send HTML to a web browser from a Django project right from the view.py Python file. A better way to handle serving HTML in Django is with Templates. In Django, a Template is simply an HTML file stored in a specific location that has the added ability to output dynamic variables and content. Rather than building up HTML in a views.py file, we can create Django Templates that have placeholders where the dynamic variables will be displayed. In order to use Templates in Django, we need to make sure to register them properly.

Django Template Location

So you are ready to create a new template for your Django project. Where do you put it? The convention in Django is to begin in your app folder, and then in that folder create a folder named templates. Then inside the templates folder, you want to create another folder that has the same name as the app itself. So if we are working on a goals app, then the template directory should be goals/templates/goals.

django template location

Creating A Template

To create a template, we can add an HTML file to the goals/templates/goals directory. Let’s name this file goal.html.

vs code django template

Let’s now add some base markup to the template. In VS Code, there is a built-in extension named Emmet that can help you type fewer thanks to quick suggestions. Make sure the value of “editor.quickSuggestions”: true, is set in settings.json if your vs code emmet abbreviation is not working.

vscode editor_quickSuggestions

Press the Tab key, and your HTML Template should now have some base markup in place. Note that we added the custom H1 tag with some text as well.

C:\python\djangoprojects\myproject\goals\templates\goals\goal.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>The Template Works!</h1>
</body>
</html>

Register Django Template

If we try to render this template via a view function it will not yet work, and we would see an error like this one.

TemplateDoesNotExist at /goals/daily

goals/goal.html

Request Method: 	GET
Request URL: 	http://127.0.0.1:8000/goals/daily
Django Version: 	3.2.4
Exception Type: 	TemplateDoesNotExist
Exception Value: 	

goals/goal.html

In order to use our templates, we must register them in Django. To register templates in Django, we can open the settings.py file and find the settings related to Templates. The out-of-box settings are shown here.

C:\python\djangoprojects\myproject\myproject\settings.py

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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',
            ],
        },
    },
]

Configure DIRS

The DIRS key in the code snippet above is used to tell Django what directory paths to look in for HTML Template files. These paths should be an absolute path and Django helps us in this regard by already providing a BASE_DIR variable higher up in the settings.py file.

# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent

Using this variable, we can now configure DIRS as shows below to make Django aware of the templates directory in our goals app.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [
            BASE_DIR / 'goals' / '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',
            ],
        },
    },
]

Send Template In HttpResponse

The use case for a template is for the HTML of that template to be sent back to the user when a particular view function triggers. To do this, the template needs to be converted to an HTML string which can be sent back with the response to the user. To do this, we can use the Django render_to_string() function. We can import this into our views.py file like so.

from django.shortcuts import redirect, render
from django.http import HttpResponse, HttpResponseRedirect
from django.urls import reverse
from django.template.loader import render_to_string

Now we can use the render_to_string() function in any of our view functions, and pass it the path to the template we want to render.

def goals_by_timeframe(request, timeframe):
    goal = goals[timeframe]
    response_data = render_to_string('goals/goal.html')
    return HttpResponse(response_data)

The code above renders our template to an HTML string and stores it in the response_data variable. At that point, we return an HttpResponse with the response_data variable. Now if we visit the proper URL to trigger that view function, we see the template is correctly displayed in the web browser.

django render_to_string function


A Better Way To Register Templates

We were able to get the template registered and working with our Django project, but there is a better way to do this. The APP_DIRS key shown is set to True. What this means is that Django will look inside of app directories by default to find template files.

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        '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',
            ],
        },
    },
]

So why did Django fail to find the template we created on our first try? The reason is that up to this point, we never registered our app as part of the INSTALLED_APPS in settings.py. Anytime you want an app you create to become part of the overall Django project, you must register it in INSTALLED_APPS. This completes several pieces of wiring between an app and the containing Django project, one of which is making Django aware of templates in that app. So we can leave the TEMPLATES settings at their defaults, and update the INSTALLED_APPS to include our newly created goals app.

INSTALLED_APPS = [
    'goals',
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]

With this change, our template continues to work, and all we had to do was add the app name to INSTALLED_APPS which registers any templates of that app with Django. For app-specific templates, this is the way to go. Simply leave APP_DIRS set to True, and add the app name to INSTALLED_APPS. This is the best practice that keeps your settings clean and maintainable.