Ningle Tutorial 2: Templates
by NMunro
Contents
- Part 1
- Part 2
Introduction
Following on from tutorial-1, we will begin extending our application, which will be the cliche “microblog” tutorial which is common these days. This time we will be focusing on how to render templates, a typical thing to do in web applications, it separates application logic from presentation.
We will be using djula as our templating system, it is analogous to jinja
or django templates
in function, if you are familiar with those you should feel right at home.
In Ningle
nomenclature, a route
is a url
, and the function that is run when a client connects to the route
is known as a controller
, I will be following this terminology in my tutorial. This distinction was not important in the previous tutorial, but I believe it is worthwhile learning the correct terms for things and using them, in Computer Science as in magic and demonology, things are much easier to reason about when you know the true names of things.
A Word About Application Design
One questions I was asked many time when I was teaching was “how do you know what to do next?”, students were overwhelmed with all the work that had to be done, they weren’t sure where to begin or if they had made a start weren’t sure what the next step was.
While I was working on the UK National Archive search engine, we were given 5 days to implement a new system from scratch, it was me (a back end developer) and a front end developer, we spent the first 4 hours of our first day discussing and deciding how we were going to work. We agreed to start on a very simple base, a simple backend that had no database connections and returned hard coded data that we agreed the front end could work with, and the most basic of html forms, with no css, just the ability to GET/POST data to/from the routes.
This enabled my team mate to access a route and get realistic looking data (even though it was fake) and I was able to use a basic html form to test the backend. Once this basic shared scafford was in place we both began working on our actual tasks. He would begin styling the form, and I would one by one connect the routes to the database and return real data.
This is the approach we will be taking with this tutorial, to have a microblog application we will need a database, an authentication system, static files etc… We would very quickly get into the weeds before writing anything anywhere close to rewarding. We will be hard coding data in controllers initially, and we will later replace it with real data and real functionality once we have gotten to that point.
In short, it’s ok to not know, necessarily when comes next, you can build things in small pieces, you can use stubs, scaffolding etc and it’s fine to figure out the next piece as you go, I sometimes don’t necessarily know what to build next, or indeed how to build it, but once I have something, it helps me because I can begin to see how the application comes together.
Adding Djula
In our previous tutorial we had to add clack
and ningle
to our asd
file, in the :depends-on()
section, after installing them with quicklisp
, we repeat this process, by first installing djula
with quicklisp
.
(ql:quickload :djula)
As we did previously, we must edit the ningle-tutorial-project.asd
file. Find the :depends-on()
section which will look like this:
:depends-on (:ningle
:clack)
And we must add :djula
to the end of the list, such that it looks like this:
:depends-on (:ningle
:clack
:djula)
Using Djula
Basic Concepts
Djula
is a template
system, if you are unfamiliar with what these are, in the context of web development, it allows you to create html pages that differ in only small ways, and inject the data that differs. In our microblog example, every user will have a timeline of sorts, and every timeline will be different, but it will share exactly the same structure, so the same template can be reused quite easily.
In short, a template
is a file that contains some pre-written content that may have data injected into that content to modify it.
Templates also allow you to extend other templates (which we will see in this tutorial), so if you wish to have a clear visual style shared across all templates you can create a base template that all others extend (which is exactly what we will be doing). In addition to passing data into templates, templates have some basic logic like branching (if) and loops (for), as well as filters for formatting or transforming data in your presentation logic.
It is worth exploring the key concepts of djula
and how to use them, even if we don’t in fact end up using them in our final project, while this wont serve as a comprehensive djula
tutorial, it will cover more than the basics we will initially use.
Integrating Djula
Before we get started working with djula
directly, we must ensure it knows how to find the templates by adding a template directory to the list of locations djula
knows to search inside. There’s no particular place specifically to do this, so I have elected to set this within the start
function.
To remind ourselves, our original start function looked like this:
We must add a single line into this to instruct djula to add our template directory.
Setting Up Templates
Of course, we must make sure that this directory exists and that a template is in the templates directory, prior to running our application, so (once again assuming your quicklisp is installed at ~
):
mkdir -p ~/quicklisp/local-projects/ningle-tutorial-project/src/templates
touch ~/quicklisp/local-projects/ningle-tutorial-project/src/templates/index.html
Now that the basics are in place, we can begin to look at some basics of djula
.
An Example Without Djula
I’d like to start with what our code might look like if we weren’t using djula
, so that its use is quite apparent, we shall return to our index
controller.
It simply returns a string and the web browser renders that string, it isn’t html
and so if we want to send html
to the web browser, we must send html
.
This isn’t a lot of html
and that’s even before we consider what to do if we want to render a different title
or h1
. We could of course use format
to dynamically inject values into the string, but would become increasingly more complicated if we needed to repeat something, or only render parts of the html
on a conditional basis, for example, what to show if the user
object was nil?
The html would grow quite a bit, and if you had shared styles and structure you’d constantly be editing it everywhere you used it for even the smallest of changes. You could of course try to store the base html in a global variable but as pages diverged with different needs this would just become even more problematic.
I trust you see the scope of the problem and the nature of the solution!
An Example With Djula
So let’s look at how we might make this easier with djula
.
We first need to edit src/templates/index.html
:
<!doctype html>
<html>
<head>
<title>{{ title }} - Y</title>
</head>
<body>
<h1>Hello, {{ user.username }}</h1>
</body>
</html>
This almost looks like normal html
, but for one unusual difference, the {{ title }}
and {{ user }}
. These are ways to inject a value from a controller into a template. In fact there are two template specific differences we are going to look at, values are wrapped in {{ }}
which we will learn about in just a moment, and {% %}
which are used for running an expression (branching, looping, etc), in effect {{ }}
is for displaying something {% %}
is for doing something.
In our example here we are only going to display the values of two variables, title, and name. To do this, we must edit our controller function:
We replace the string "Hello World"
with the call to djula:render-template*
. It takes the name of the template to render (in this case our “index.html” file), it also takes an optional stream, which since we are not needing to redirect to any other streams we set this to nil
and any optional key word arguments that will be the named variables passed into the template.
You can experiment with changing the values passed in (remembering to recompile your application) to see that the template is changed.
I do hope you agree that this looks much more manageable, it certainly cuts down on the amount of html you need to write and maintain, but I mentioned that we would see how expressions can be used. In this example, if we didn’t pass through a title, or user, nothing would show in the template. We might make a mistake, or perhaps load some data from a database and there simply isn’t a valid value returned and we would want to display something rather than nothing. That’s when these expressions come in!
Conditional Rendering (branching)
Let’s begin first by editing our index.html
file.
<!doctype html>
<html>
<head>
{% if title %}
<title>{{ title }} - Y</title>
{% else %}
<title>Welcome to Y</title>
{% endif %}
</head>
<body>
<h1>Hello, {{ user.username }}</h1>
</body>
</html>
We have made a slight change in the template that will render the title passed into the template if it is given, however if for whatever reason it is omitted, is nil
, or ""
then a default title is rendered instead.
If you wish to experiment by removing the :title
argument in the djula:render-template*
function call, and see how this affects the way the template is rendered.
Repeated Rendering (loops)
Our microblog application must, sooner or later, begin to render posts by other users. It is trivial enough to pass posts from our controller to our template, it’s not any more difficult than what we have done previously, it’s just more code.
The controller has been modified to mock our microblog data, in this case something representing a logged-in user, and a list of posts that might be representitive of a timeline feature, however, now that we have a list of posts, we shall have to use a loop in our template to repeatedly print each post.
As discussed in the previous section, we must use the {% %}
expression braces to do things in our templates and a loop is indeed doing something, it’s doing something repeatedly! So, we return to editing our index.html
file and modify it to look like the following:
<!doctype html>
<html>
<head>
{% if title %}
<title>{{ title }} - Y</title>
{% else %}
<title>Welcome to Y</title>
{% endif %}
</head>
<body>
<h1>Hello, {{ user.username }}</h1>
{% for post in posts %}
<div>
<p>{{ post.author.username }} says: <b>{{ post.content }}</b></p>
</div>
{% endfor %}
</body>
</html>
The change is introduced under the <h1>
tag, we use the {% %}
to run a for
loop, well, technically a foreach
loop, that iterates of the variable posts
that is passed in from the controller. As it loops it will create a new <div>
that contains information about the post, including its author and the post content.
Our basic microblog app is beginning to take shape, but there’s one final aspect of djula
that we must look into to assist us in overall template management.
Template Inheritance
The best practice for working with templates is to create inheritance so that you can build bases upon which to create more specialized templates without worrying about repeated, shared, html. So, we shall restructure our application to create a base.html
upon which our index.html
will extend.
<!doctype html>
<html>
<head>
{% if title %}
<title>{{ title }} - Y</title>
{% else %}
<title>Welcome to Y</title>
{% endif %}
</head>
<body>
<div>Y: <a href="/">Home</a></div>
<hr>
{% block content %}
{% endblock %}
</body>
</html>
This is our base.html
file, much of it will appear to be familiar, in fact it looks almost like our index.html
file, however where the posts were, a new expression block is introduced the block
, blocks are given a name, in this case content
, but in reality can be called whatever you want. You might have {% block nav %}
, {% block header %}
, {% block footer %}
, whatever you want really, but blocks are closed with {% endblock %}
.
In a base template such as our titlular base.html
these blocks are often empty, but as you can see below in our rewritten index.html
we override the content of these blocks.
{% extends "base.html" %}
{% block content %}
<h1>Hi, {{ user.username }}!</h1>
{% for post in posts %}
<div>
<p>{{ post.author.username }} says: <b>{{ post.content }}</b></p>
</div>
{% endfor %}
{% endblock %}
The first thing we do is extend
the base.html
file, having done that we inherit everything from the base and do not need to rewrite all the common shared html
that we wrote in the base.html
file. As mentioned above we open the content block
(in the same manner as it was defined in the base.html
) as fill in only the html
we need to display.
Conclusion
To recap, after working your way though this tutorial you should be able to:
- Describe, discuss, and explain what a template is.
- Explain why templates are beneficial.
- Create a base template that is extended by another template.
- Construct a route and controller that renders a template.
I hope that you have found this helpful, it’s not a comprehensive introduction to djula
by any stretch of the imagination and we will be revisiting it later on in this tutorial series, we need to look into filters
at a later date (when our application needs them). In the meantime I would suggest that you read the djula documentation for further information.
In the next tutorial we will be looking at how to render static files
(images, css, js, etc) using lack
middleware
.
Github
The link for this tutorial is available here.