Previously we’ve set the route handler’s response.text to very simple Hello world strings. Now we’ll use the Mako template engine to build full-featured HTML pages.

In the same folder as our demo.py app, create a static/templates/ folder and a static/css/ folder.

Create a static/templates/base.html file with the following code:

<!DOCTYPE html>
<html lang='en'>
        <title><%block name='page_title'/></title>
        <meta charset='utf-8'>
        <%block name='static'>
            <link rel='stylesheet' href='${STATIC}/css/demo.css'>
        <%block name='content'/>

Create a static/templates/main.html file with the following code:

<%inherit file='base.html'/>
<%block name='page_title'>${title}</%block>
<%block name='content'>
    <p> Hello this is the ${page} page. Query string: ${query}</p>

Create a static/css/templates/demo.css file with the following code:

body {
    font-family: Verdana, sans-serif;
    max-width: 700px;
    padding: 1rem;
    margin: 0 auto !important;

Add the following lines to demo.py:

from drakken.template import render

def query(request, response):
    context = dict(
        title='Query page',
    response.text = render(request, 'main.html', context=context)

Launch the app and visit You should see the message Hello this is the /query page. Query string: name=Stuart.

Template inheritance

The main.html template inherits from the base.html template. Template inheritence is useful because on a real-world website many of the pages have common elements that can be placed in a parent (base) template to prevent duplication of effort.


Variables needed to render the template are returned in the context dictionary. In the example above, the ${STATIC} variable is built into Drakken, while the ${title} and ${page} variables were created for our demo. You can add as many variables to the context dictionary as you’d like.

The ${user} context variable represents the User object currently logged in. The {CSRF} context variable is the Cross Site Request Forgery (CSRF) token used for securing form submissions. Both the ${user} and ${CSRF} variables are built into Drakken.

Named URLs

If you have a website with lots of templates containing hard coded links then changing those links by hand can be boring and fraught with error. An easier way is to use named URLs which allows you to change a URL in one place instead of dozens.

In demo.py add a name argument to the about page controller:

@app.route('/about-us/', name='about')
 def about(request, response):
    response.text = 'We love Python!'

In templates/main.html add a named URL:

<p> Hello this is the ${page} page. Query string: ${query}</p>
<p>Read <a href="{% url about %}">about us</a>.</p>

Launch the app and visit You should see the message Hello this is the /query page. Query string: name=Stuart.

Click the about us link and you should be at the /about-us page.

Static files

Static files like CSS, Javascript, and image files typically go in a static folder in the root folder of your app. In the above example the base.html template calls the static file demo.css. A custom configuration file allows you to set the ${STATIC} folder name to whatever you want.

Route handling for static files

Another way to return a static file is by creating a route handler for it. In the example below, robot() returns a file robots.txt residing in the top-level templates folder.

from drakken.template import read

def robot(request, response):
    response.text = read('robots.txt')