How to work with templates¶
django CMS uses Django’s template system to manage the layout of the CMS pages.
Django’s Template System¶
Django’s template language is designed to strike a balance between power and ease. It’s designed to feel comfortable to those used to working with HTML. If you have any exposure to other text-based template languages, such as Smarty or Jinja2, you should feel right at home with Django’s templates.
The template system, out of the box, should be familiar to those who have worked with desktop publishing or web design. Tags are surrounded by {% and %} and denote the actions like loops and conditionals. Variables are surrounded by {{ and }} and get replaced with values when the template is rendered.
Learn more about Django’s template system in the Django documentation.
Django CMS and Django’s Template System¶
Django templates¶
You are totally free on how to name your templates, but we encourage you
to use the general Django conventions, including letting all templates inherit
from a base template by using the extends template tag or putting templates
in a folder named after the application providing it.
Note
Some django CMS apps, like django CMS Alias, assume the base template is
called base.html. If you happen to prefer a different name for the base
template and need to use such apps, you can create a base.html template
that just consists of the {% extends "your_base_template.html" %} tag.
A fresh installation of django CMS using the quickstarter project or the
djangocms command comes with a default template that for reasons of
convenience is provided by
django CMS frontend
and based on Bootstrap. We encourage you to create your own templates
as you would do for any Django project.
Generally speaking, django CMS is wholly frontend-agnostic. It doesn’t care what your site’s frontend is built on or uses: You are free to decide which CSS framework or JS library to use (if any).
When editing, the frontend editor will replace part of the current document’s DOM. This might require some JS widgets to be reinitialized. See Frontend integration for more information.
CMS templates¶
You need to configure which templates django CMS should use. You can do this by
either setting the CMS_TEMPLATES or the CMS_TEMPLATES_DIR
settings.
You can select the template by page (and language) in the page menu of django
CMS’ toolbar. By default, a new page uses the same template as its parent page
(this is template assignment, not Django {% extends %} inheritance — see
Template inheritance pattern below). A root page uses the first template in
CMS_TEMPLATES if no other template is explicitly set.
To work seamlessly with django CMS, your templates should include the
{% cms_toolbar %} tag right as the first item in your template’s
<body>. This tag will render the toolbar for logged-in users.
Note
The toolbar can also be displayed in views independent of django CMS. To provide a consistent user experience, many projects include the toolbar in their base template and share it with the whole Django project.
Also, you need to tell django CMS where to place the content of your pages. This is done using placeholders. A placeholder is a named area in your template where you can add content plugins. You can add as many placeholders as you want to your templates.
To add a placeholder to your template, use the
{% placeholder "name" %} template tag. The name is the name of the template
slot. It will be shown in the structure board of the frontend editor. Typical
names are “main”, “sidebar”, “footer”, etc.
Finally, you need to add {% render_block "css" %} in the <head> section
of your CMS templates and {% render_block "js" %} right before the closing
</body> tag of your CMS templates. This will render the CSS and JavaScript
at the appropriate places in your CMS templates.
django CMS uses django-sekizai
to manage CSS and JavaScript. To use the sekizai tags, you need to load the
sekizai_tags template tags in your template: {% load sekizai_tags %}.
Template inheritance pattern¶
django CMS projects typically organize their templates into three layers, using Django’s
standard {% extends %} and {% block %} mechanics:
Base template (usually
base.html) — the shared chrome:<!DOCTYPE>,<head>,<body>,{% cms_toolbar %}, and the sekizai{% render_block "css" %}/{% render_block "js" %}tags. It defines empty{% block %}slots that per-page content will fill.CMS page template — extends
base.htmland fills those blocks withplaceholdertags for page-specific content. These are the templates you list inCMS_TEMPLATESand select in the page’s Advanced settings.Apphook or model template — extends
CMS_TEMPLATE(see CMS_TEMPLATE below) and overrides blocks with application output. This way an app view inherits whichever page template the current CMS page is using — including the toolbar, sekizai blocks, and any surrounding layout — without hardcoding a base template path.
Layers 1 and 2 are plain Django inheritance. Layer 3 is the django CMS-specific trick:
CMS_TEMPLATE is a context variable holding the current CMS page’s template path, so
{% extends CMS_TEMPLATE %} reuses whichever template the CMS is currently rendering.
Where to put placeholders¶
Page-specific content (main content area, article body) → the CMS page template (layer 2). Each CMS page template declares its own slot set.
Site-wide content that is identical on every page (a promotional banner shared across all pages) → declare once in the base template (layer 1) so it renders everywhere, or use a
static_alias(see Static aliases below) if editors should manage it centrally from Django admin.Apphook or model-specific content → the app’s template (layer 3); the placeholder resolves against the current page or the toolbar object.
Warning
If you put a placeholder inside a {% block %} that a child template
overrides without calling {% block.super %}, the placeholder disappears from the
rendered page. Keep shared placeholders outside overridable blocks, or make sure
children call {% block.super %} when they mean to keep the base content.
Example¶
Here is an example of a simple template that uses placeholders:
{% extends "base.html" %}
{% load cms_tags djangocms_alias_tags %}
{% block title %}{% page_attribute "page_title" %}{% endblock title %}
{% block content %}
<header>
{% placeholder "header" %}
</header>
<main>
{% placeholder "main" %}
</main>
<footer>
{% static_alias "footer" %}
</footer>
{% endblock content %}
In this example the child template:
extends
base.html— reusing the shared chrome without repeating it;fills
{% block title %}and{% block content %}— these bodies replace the empty blocks of the same name in the base template;declares three placeholders (
header,main,footer) inside{% block content %}— each becomes an editable slot in the structure board.
Everything in the base template outside those blocks — <html>, <head>,
{% cms_toolbar %}, the sekizai {% render_block %} tags — is inherited unchanged.
The underlying base template could look like this:
{% load cms_tags sekizai_tags %}
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}{% endblock title %}</title>
{% render_block "css" %}
</head>
<body>
{% cms_toolbar %}
{% block content %}{% endblock content %}
{% render_block "js" %}
</body>
</html>
Static aliases¶
Added in version 4.0.
Note
Using static_alias requires the installation of
djangocms-alias to work.
The package djangocms-alias provides an admin page in Django admin where special types of placeholders called “static aliases” can be managed and its contents edited.
Frequent Use Cases:
Editors wish to manage repeated content centrally (DRY - don’t repeat yourself)
Developers wish to add CMS functionality to their custom application’s templates
Repeated content: Often, content areas such as a footer, a header or a sidebar have identical content across all pages of a website. djangocms-alias provides a Django admin page for editors to manage such general site-wide content in one place.
Custom applications: Templates in custom applications usually follow some
well-defined business logic which is normally hard-coded in the template.
However the same templates might include areas of “static” content, i.e.
content that editors wish to manage. The django CMS placeholder tag
works in templates attached to the django CMS
Page model, or in templates rendered by apphook
views (see Using placeholders on an apphooked page). For content areas
that are not tied to a page or apphook,
djangocms-alias
closes the gap by providing editors central access to such custom content areas.
CMS_TEMPLATE¶
CMS_TEMPLATE is a context variable whose value is the template path for the current
CMS page (or apphook page), or the first template in CMS_TEMPLATES when the
URL is not managed by the CMS.
Use it as the base for any app template that should blend into CMS pages — write
{% extends CMS_TEMPLATE|default:"my_default_template.html" %} instead of hardcoding
a base-template path. The app template will then pick up the toolbar, sekizai blocks,
and any layout the current page template provides, even if editors later switch the
page to a different template.
Without CMS_TEMPLATE, an app template with a hardcoded
{% extends "myproject/base.html" %} would always render with myproject/base.html
regardless of which page template the CMS is rendering — causing layout drift whenever
editors change the page’s template.
Example: cms template
{% load cms_tags sekizai_tags %}
<html>
<head>
{% render_block "css" %}
</head>
<body>
{% cms_toolbar %}
{% block main %}
{% placeholder "main" %}
{% endblock main %}
{% render_block "js" %}
</body>
</html>
Example: application template
{% extends CMS_TEMPLATE %}
{% load cms_tags djangocms_alias_tags %}
{% block main %}
{% for item in object_list %}
{{ item }}
{% endfor %}
{% static_alias "sidebar" %}
{% endblock main %}
CMS_TEMPLATE memorises the path of the cms template so the application
template can dynamically import it.
Template assignment across translations and versions¶
This section is about which template file is assigned to a page content, not about
Django’s {% extends %} / {% block %} inheritance (see
Template inheritance pattern for that).
Default behavior (without versioning)¶
In django CMS (version 4 and above), when creating page content translations, all content is immediately published. When creating a translation of an existing page, the template from the original page content is copied to the new translation. This behavior can be seen in the create_translation method. The template is explicitly copied from the original page content to ensure consistent layout across languages.
Note for django CMS versions prior to 4.2:
In older versions of django CMS (prior to 4.2), when creating page content translations, the template is not automatically copied from the original page content. Instead, the default site template (or the template from the last published version) is applied, and manual adjustments may be necessary to ensure consistency.
Behavior with djangocms-versioning¶
When using djangocms-versioning, pages and their content can exist in different states (draft, published, etc.). This introduces some nuances in template inheritance:
When you create a page and publish it, the template is set and published
When creating a translation of a page content, the new translation will inherit the template from the draft version of the main language page content if one exists
If no draft version exists in the main language, the template will be inherited from the published version instead
This behavior ensures that new translations automatically pick up any template changes that are in progress (draft state) in the main language, maintaining consistency across translations even before changes are published.