Skip to main content

Mako template engine for Django.

Project description

Mako for Django

Mako powered template backend for Django.

Table of Contents

Overview

This backend integrates Mako directly into Django's template engine API. It supports Django's configuration, template discovery within app directories, and context processors, while extending them with Mako's syntax, performance, and detailed error handling.

Preview: Contextual line information TemplateSyntaxError preview
Preview: Runtime errors Runtime error preview
Preview: Template postmortem TemplateDoesNotExist preview

Motivation

Mako's multi-zoned inheritance feature can be used with the <%def> tag to encapsulate structure and behavior, enabling modular and maintainable templates. This approach provides a component-like system similar to React (JSX) or other modern frameworks that support props and named/default slots. For technical details, see the Defs and Blocks section in the Mako documentation.

Demonstration

Component definition: button.html.mako
<%def
  name="base_button(
    class_name=None,
    icon=None,
    label=None,
    round=False,
    rounded=False,
  )"
>
  <button
    class="${ clsx([
      'button',
      ('button--round', round),
      ('button--rounded', rounded),
      class_name,
    ]) }"
  >
    % if icon:
      <span class="button__icon">
        ${ icon() }
      </span>
    % endif
    % if label:
      <span class="button__label">
        ${ label() }
      </span>
    % endif
  </button>
</%def>

<%def name="basic_button(class_name=None, rounded=False)">
  <%self:base_button
    class_name="${ ['button--basic', class_name] }"
    icon="${ getattr(caller, 'icon', None) }"
    label="${ getattr(caller, 'label', None) }"
    rounded="${ rounded }"
  />
</%def>

<%def name="icon_button(class_name=None, round=False)">
  <%self:base_button
    class_name="${ ['button--icon', class_name] }"
    icon="${ getattr(caller, 'body', None) }"
    round="${ round }"
  />
</%def>

[!TIP] The clsx function is imported from clsx-py project, to manage class names dynamically.

Component usage: page.html.mako
<%namespace name="button" file="button.html.mako" />

<%button:icon_button class_name="sample-button">
  ➖
</%button:icon_button>

<%button:icon_button class_name="sample-button" round="${ True }">
  ➕
</%button:icon_button>

<%button:basic_button class_name="sample-button">
  <%def name="icon()">✖️</%def>
  <%def name="label()">Cancel</%def>
</%button:basic_button>

<%button:basic_button class_name="sample-button" rounded="${ True }">
  <%def name="icon()">⚡</%def>
  <%def name="label()">Trigger</%def>
</%button:basic_button>
Output
<button class="button button--icon sample-button">
  <span class="button__icon"></span>
</button>

<button class="button button--round button--icon sample-button">
  <span class="button__icon"></span>
</button>

<button class="button button--basic sample-button">
  <span class="button__icon">✖️</span>
  <span class="button__label">Cancel</span>
</button>

<button class="button button--rounded button--basic sample-button">
  <span class="button__icon"></span>
  <span class="button__label">Trigger</span>
</button>

Installation

Available on PyPI:

pip install mako-for-django

Usage

Minimal configuration in settings.py:

TEMPLATES = [
    {
        "BACKEND": "django_mako.MakoEngine",
        "DIRS": [
            BASE_DIR / "mako",
        ],
        "APP_DIRS": True,
        "OPTIONS": {},
    },
]

[!IMPORTANT] By default, templates within apps should be placed under a mako directory.

Example: Extending OPTIONS
MAKO_LOOKUP_OPTIONS = {
  "cache_enabled": True,
  # https://beaker.readthedocs.io/en/latest/
  "cache_impl": "beaker",
}

MAKO_TEMPLATE_OPTIONS = {
  "encoding_errors": "strict" if DEBUG else "htmlentityreplace",
}

TEMPLATES = [
    {
        "BACKEND": "django_mako.MakoEngine",
        "DIRS": [
            BASE_DIR / "mako",
        ],
        "APP_DIRS": True,
        "OPTIONS": {
            "lookup": {
                **MAKO_LOOKUP_OPTIONS,
            },
            "template": {
                **MAKO_TEMPLATE_OPTIONS,
            },
        },
    },
]
Example: Using Mako alongside DjangoTemplates
SHARED_TEMPLATE_CONTEXT_PROCESSORS = [
    "django.template.context_processors.debug",
    "django.template.context_processors.request",
    "django.contrib.auth.context_processors.auth",
    "django.template.context_processors.tz",
    "django.template.context_processors.i18n",
    "django.contrib.messages.context_processors.messages",
    "django.template.context_processors.static",
    "django.template.context_processors.media",
]

# Context processors to use with Mako backend only.
MAKO_TEMPLATE_CONTEXT_PROCESSORS = [
    "django_mako.template.context_processors.url",
]

TEMPLATES = [
    {
        "BACKEND": "django_mako.MakoEngine",
        "DIRS": [
            BASE_DIR / "mako",
        ],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                *SHARED_TEMPLATE_CONTEXT_PROCESSORS,
                *MAKO_TEMPLATE_CONTEXT_PROCESSORS,
            ],
        },
    },
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [
            BASE_DIR / "templates",
        ],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                *SHARED_TEMPLATE_CONTEXT_PROCESSORS,
            ],
        },
    },
]

Tutorial

This tutorial guides you through creating a minimal Django project using Mako templates. Follow the steps to set up the project, add an application, create layout and page templates, and finally render a simple page in the browser.

By the end of this tutorial, the project structure should look like this:

demo/
├── demo/
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── index/
│   ├── mako/
│   │   └── index/
│   │       └── views/
│   │           └── index.html.mako
│   ├── migrations/
│   │   └── __init__.py
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
├── mako/
│   └── layout.html.mako
└── manage.py
  1. Create a new Django project:
django-admin startproject demo
cd demo
  1. Create a new app inside the project:
python manage.py startapp index
  1. Enable the app in settings.py:
INSTALLED_APPS = [
    "index",
]
  1. Configure MakoEngine in settings.py:
TEMPLATES = [
    {
        "BACKEND": "django_mako.MakoEngine",
        "DIRS": [
            BASE_DIR / "mako",
        ],
        "APP_DIRS": True,
        "OPTIONS": {},
    },
]
  1. Add layout template mako/layout.html.mako:
<!DOCTYPE html>
<html>
  <head>
    <title><%block name="title">Demo</%block></title>
  </head>
  <body>
    ${ next.body() }
  </body>
</html>
  1. Create page template index/mako/index/views/index.html.mako:
<%inherit file="/layout.html.mako" />

<%block name="title">${ title } | ${ parent.title() }</%block>

<h1>${ title }</h1>
  1. Add view in index/views.py:
from django.shortcuts import render


def index(request):
    return render(
        request,
        # The template path, relative to `index/mako` directory.
        "/index/views/index.html.mako",
        {
            "title": "Mako for Django",
        },
    )
  1. Wire up urls.py:
from django.urls import path
from index.views import index


urlpatterns = [
    path("", index),
]
  1. Run the server:
python manage.py runserver

After running the server, you can visit http://127.0.0.1:8000/.

Checkout the e2e directory for more examples.
git clone https://github.com/ertgl/mako-for-django.git
cd mako-for-django/e2e
make
python manage.py runserver

References

Name

Published on PyPI as mako-for-django. The import name django_mako is chosen for brevity.

License

This project is licensed under the MIT License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mako_for_django-1.0.0.tar.gz (8.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mako_for_django-1.0.0-py3-none-any.whl (15.2 kB view details)

Uploaded Python 3

File details

Details for the file mako_for_django-1.0.0.tar.gz.

File metadata

  • Download URL: mako_for_django-1.0.0.tar.gz
  • Upload date:
  • Size: 8.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.12

File hashes

Hashes for mako_for_django-1.0.0.tar.gz
Algorithm Hash digest
SHA256 943b97a35d52af8556893ab3d66e1508102524fb3892107dc2927d0af220bb30
MD5 befdf65284847465c2d5284b45496f02
BLAKE2b-256 55faa21d7575dec3e0270a78123de9b1729f20fc83238525b9c861f6979a3d5b

See more details on using hashes here.

File details

Details for the file mako_for_django-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mako_for_django-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 366080e46bb791cafc1caebe3ffc9ad67747b1272e6cc87c2fb06043b2360f24
MD5 fc783b3537bc1e4d54121852b5070072
BLAKE2b-256 d4b1d695fc3276ed828a12f4db3970c8996a397cb24161c9907d49c549371cb9

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page