Templates evaluations occur in CL-USER package by default. It is likely that your templates need evaluations to happen in some of your application packages instead. This need typically arises when trying to evaluate {{ object.method }}
where method is a generic function (accessing slots works fine).
These are the ways to control the template package:
*template-package*
to a package of yours.
*template-package*
before rendering the template.
Like:
(let ((djula:*template-package* (find-package :app-package))) (djula:render-template* "app-template.html"))
set-package
tag. Note that as of now, this sets the *template-package*
globally, not just for that template. So you may want to make sure to start all of your templates with a set-package
tag to set the correct package for each template.
The most powerful – and thus the most complex – part of Djula’s template engine is template inheritance. Template inheritance allows you to build a base “skeleton” template that contains all the common elements of your site and defines blocks that child templates can override.
You can also refactor independent template sections in their own file and include it in the main template, passing it the required arguments.
It’s easiest to understand template inheritance by starting with an example:
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="style.css" /> <title>{% block title %}My amazing site{% endblock %}</title> </head> <body> <div id="sidebar"> {% block sidebar %} <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> {% endblock %} </div> <div id="content"> {% block content %}{% endblock %} </div> </body> </html>
This template, which we’ll call base.html
, defines a simple HTML skeleton
document that you might use for a simple two-column page. It’s the job of
“child” templates to fill the empty blocks with content.
In this example, the block
tag defines three blocks that child
templates can fill in. All the block
tag does is to tell the template
engine that a child template may override those portions of the template.
A child template might look like this:
{% extends "base.html" %} {% block title %}My amazing blog{% endblock %} {% block content %} {% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %} {% endblock %}
The extends
tag is the key here. It tells the template engine that
this template “extends” another template. When the template system evaluates
this template, first it locates the parent – in this case, “base.html”.
At that point, the template engine will notice the three block
tags
in base.html
and replace those blocks with the contents of the child
template. Depending on the value of blog_entries
, the output might look
like:
<!DOCTYPE html> <html lang="en"> <head> <link rel="stylesheet" href="style.css" /> <title>My amazing blog</title> </head> <body> <div id="sidebar"> <ul> <li><a href="/">Home</a></li> <li><a href="/blog/">Blog</a></li> </ul> </div> <div id="content"> <h2>Entry one</h2> <p>This is my first entry.</p> <h2>Entry two</h2> <p>This is my second entry.</p> </div> </body> </html>
Note that since the child template didn’t define the sidebar
block, the
value from the parent template is used instead. Content within a {% block %}
tag in a parent template is always used as a fallback.
You can use as many levels of inheritance as needed. One common way of using inheritance is the following three-level approach:
base.html
template that holds the main look-and-feel of your
site.
base_SECTIONNAME.html
template for each “section” of your
site. For example, base_news.html
, base_sports.html
. These
templates all extend base.html
and include section-specific
styles/design.
This approach maximizes code reuse and makes it easy to add items to shared content areas, such as section-wide navigation.
Here are some tips for working with inheritance:
{% extends %}
in a template, it must be the first template
tag in that template. Template inheritance won’t work, otherwise.
{% block %}
tags in your base templates are better. Remember,
child templates don’t have to define all parent blocks, so you can fill
in reasonable defaults in a number of blocks, then only define the ones
you need later. It’s better to have more hooks than fewer hooks.
{% block %}
in a
parent template.
{{ block.super }}
variable will do the trick. This is
useful if you want to add to the contents of a parent block instead of
completely overriding it. Data inserted using {{ block.super
}}
will not be automatically escaped (see the next section), since
it was already escaped, if necessary, in the parent template.
{% endblock %}
tag. For example:
{% block content %} ... {% endblock content %}
In larger templates, this technique helps you see which {% block %}
tags are being closed.
Finally, note that you can’t define multiple block
tags with the same
name in the same template. This limitation exists because a block tag works in
“both” directions. That is, a block tag doesn’t just provide a hole to fill –
it also defines the content that fills the hole in the parent. If there were
two similarly-named block
tags in a template, that template’s parent
wouldn’t know which one of the blocks’ content to use.
include
loads a template, renders it with the given (optional) variables and inserts its content into the calling template.
For example, we have this first template that renders a list of blog entries:
{% for entry in blog_entries %} <h2>{{ entry.title }}</h2> <p>{{ entry.body }}</p> {% endfor %}
During development, we realize that rendering a blog entry is more convoluted than first planned, so we want to refactor the blog entry template logic in its own file. And most of all, we plan on rendering a blog entry on another part of the site, so we want to re-use the rendering logic.
We create a new template in includes/blog-entry.html
and we use the {% include %}
template tag, giving it an entry object as argument:
{% for entry in blog_entries %} {% include "includes/blog-entry.html" :entry entry %} {% endfor %}
See also the ssi
tag for Server-Side Includes.