Jinja Templates - Django Web Development Tutorial

Welcome to part 3 of our Django web development with Python tutorial. Now that we have a basic understanding of how Django works, let's try to build a very basic type of website. For this, we're going to build a very simple personal website that basically gives a sort of "about me," along with a blog. As simple as this may sound, it will actually let us exercise quite a few Django principles, ending with beginning a content management system, like a blog. We will also get to explore a bit about design.

At the moment, if we attempt to visit our homepage, we get a 404, since we have nothing corresponding to it. Let's go ahead and make a new app, calling it personal, since this is our personal website.

python manage.py startapp personal

So we've added an app, and we of course fully intend to use it, so what do we need to do? Install! Heading to mysite/settings.py, find INSTALLED_APPS


You can go ahead and just delete our webapp app, that was just for simple showing. Next, we need to actually point to this new personal app. Open mysite/urls.py:

from django.conf.urls import url, include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', include('personal.urls')),

Here, we're adding a new url pattern '^$', which just quite easily means a pattern that starts, and ends, with nothing, hence the "index" or "home" page. Only one problem, this file doesn't exist! Okay, let's bop on over to personal/urls.py:

from django.conf.urls import url
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index')]

This should look very familiar. It is identical to our old webapp/urls.py. Once again, the pattern is just starts and ends with nothing. If that's the case, boom, we return views.index...which doesn't quite have anything either. Okay, let's do that. Head to personal/views.py

from django.shortcuts import render

def index(request):
    return render(request, 'personal/home.html')

This is slightly new. Here, we are bringing in "render," rather than that http response from before. Render takes the request parameter first, then the template to render, then an optional dictionary of variables to pass through to the template. For now, we keep it simple. We just simply want to load a home.html template. Of course, however, that doesn't yet exist. Okay, let's do that, but first let's explain the magic of templates and other relatively local directories. With templates, and later on static files, you will be putting your templates in a templates directory, but each app is going to have its own templates. That said, the entire website itself may have templates too, and these templates may actually simultaneously be used.

For example, generally, websites look very similar on their various pages, because they follow a template, usually referred to as a header. The header contains things like the navigation bar, maybe a banner image, and so on. This header stays the same, and should be contained in one main file. Imagine if you had a website with 100 unique pages, each containing the code for the navigation bar, and you wanted to change a button on it. You would have to edit 100 files, and that's very tedious! Thus, we have templates, like headers. That said, with Django, you're going to have headers as templates, and then other templates that "extend" these headers and act as parts.

Thus, you're going to have main-website templates, and then app-specific templates. They are not likely to be reasonably kept in the same place. Enter Django magic. Turns out, you just can have multiple template directories, one per app. Later, in your actual templates, you can just reference the relative path, and Django will just figure it out. Even if you are using one template from one app, and another template from another app. Seriously, it's sorcery, there is no other explanation. The same is true for static files, which you will see soon enough. Alright, so now that we understand to expect this magic, we wont be so surprised when it happens. First, we'll make a templates dir for the personal website: personal/templates. Since our website is indeed mainly focused on the personal app, we'll go ahead and contain the header file here.

Now, we *could* get away with putting the templates right on in here, but, if we want to take part in the Django sorcery with relative directories, we need to actually make another directory, called personal, basically the same as our app name. You will do this in every case. The reason why it wont work without protecting it one step further by the app name is Django is going to search for the template by name. You may have multiple header templates, maybe multiple "home" templates for various "homes" of the apps, and so on. To make sure you don't accidentally wind up conflicting, you add the app's name, so it's a part of the dynamic reference. Thus, the path starting from the root project, mysite, we have directories: mysite/personal/templates/personal. Now we're ready for some templates. First, we'll create a header file. Something super simple for now:

<!DOCTYPE html>
<html lang="en">

	<title>Harrison Kinsley</title>
	<meta charset="utf-8" />

<body class="body" style="background-color:#f6f6f6">
	   {% block content %}
	   {% endblock %}	


If you need an explanation on the html here, check out the video. The important Django-related bit is:

	   {% block content %}
	   {% endblock %}	

...except that's not Django! It's not really Python either. A wild Jinja has appeared, Jinja2 specifically. Jinja is a Python templating engine, aimed at helping you to do dynamic things with your HTML like passing variables, running simple logic, and more! With Jinja, you will notice we are using {% %}, this denotes logic. For variables, you will see {%{% }}. The use of block content and endlock is one of the two major ways of incorporating templates within templates. This method is generally used for header/template combinations, but there is another you could use that I will show later. Next, let's create another HTML file that will serve as whatever will fill this block content. If you remember from 5 years ago, our intention was to serve a home.html, and now we finally have our chance!


{% extends "personal/header.html" %}
{% block content %}
<p>Hey! Welcome to my website! Well, I wasn't expecting guests. Um, my name is Harrison. I am a programmer.</p>
{% endblock %}

Much of this code is actually just Jinja logic, with just a simple sentence that is actually what will be generated. This is just a very simple example, normally there will be more here. What will wind up happening, however, is, when we tell Django to open this home.html file, it will be read that this file "extends" header.html, and everything in the block content will be placed inside the block content logic that we built into the header.html file.

After much work, we're finally read to see our result! Go ahead and run the server, and visit your homepage You should get whatever you put in the home.html file. If you view the source, you will see that your other code is there, it's just that our header file is actually quite boring at the moment.

Quite a lot like the extends functionality, you can also "include" html. Where extends only extends a specific page, usually something like a header, you can also use include to include a bit of HTML dynamically. An example of an area where I have used includes is with comment boxes, ads, and other dynamic content. I have the include statements on a lot of pages. Whenever I want to modify the code on all of those pages for those elements, I just need to edit the included file once to affect all of the files. Let's make a simple example. First, in mysite/templates/personal/includes/htmlsnippet.html (you do not already have an includes directory here, make one).

{% block content %}
<p>Whoa, check me out, I am included!</p>
{% endblock %}

As you can see, we use the block content logic tags. This is the snippet we may want to include elsewhere, so let's try it in the homepage:mysite/personal/templates/personal/home.html

{% extends "personal/header.html" %}
{% block content %}
<p>Hey! Welcome to my website! Well, I wasn't expecting guests. Um, my name is Harrison. I am a programmer.</p>

{% include 'personal/includes/htmlsnippet.html' %}

{% endblock %}

Now, refresh the homepage, and you should have the new included text too! As you can imagine, these include snippets would or could be a lot more complex, and included in many other templates.

In the next tutorial, we're going to discuss design with HTML/CSS and Bootstrap.

Download the entire site's code for this tutorial here: Part 3

The next tutorial:

  • Django Web Development with Python Introduction
  • First Website - Django Web Development Tutorial
  • Jinja Templates - Django Web Development Tutorial
  • Design with HTML/CSS - Django Web Development Tutorial
  • Jinja Variables - Django Web Development Tutorial
  • Beginning a Blog - Django Web Development Tutorial
  • Views and Templates - Django Web Development Tutorial
  • Database migrations - Django Web Development Tutorial
  • Admin control panel - Django Web Development Tutorial
  • Finishing blog - Django Web Development Tutorial
  • Publishing Django Project to a web server tutorial
  • Securing Django web server with SSL - HTTPS and Lets Encrpyt