Django Templates


Templates are only used for Inertiajs layouts, api docs and emails. All of the other components are setup via the frontend.

Templates Folder Layout

text
project/
├── .envs   
├── apps 
├── templates    ---> templates folder
│   ├── pages.   ----> only one page. api docs
│   ├── templated_email  ---> email templates
│   ├── layouts          ---> inertia js layouts
│   ├── 403.html
│   ├── 404.html
│   ├── 500.html
│   ├── base.html       ---> base template for the website.
│   ├── robots.txt

Main Template

The main template is base.html which is extended by all the inertia layout template.

Here is the full template.

text
{% load static i18n vanty_tags django_vite %}
<!DOCTYPE html>
{% get_current_language as language_code %}
<html id="id-html" lang="{{ language_code }}" class="h-full w-full" data-theme="dark">

  <head>
    <title>{% spaceless %}{% block title %}Home{% endblock %}{% endspaceless %} </title>
    <meta charset="UTF-8">
    <meta name="msapplication-TileColor" content="#da532c">
    <meta name="theme-color" content="#ffffff">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="copyright" content="{{ site_meta.SITE_NAME }}{% now "Y" %}">
       {% block favicon %}
      <link rel="apple-touch-icon" sizes="180x180" href="{% static 'favicon/apple-touch-icon.png' %}">
      <link rel="icon" type="image/png" sizes="32x32" href="{% static 'favicon/favicon-32x32.png' %}">
      <link rel="icon" type="image/png" sizes="16x16" href="{% static 'favicon/favicon-16x16.png' %}">
      <link rel="manifest" href="{% static 'favicon/site.webmanifest' %}">
    {% endblock favicon %}
    {% block seo-meta %}<meta name="robots" content="index,follow">{% endblock %}

    {% block site_assets %}{% endblock %}
    <script>
    let isDarkMode = window.matchMedia('(prefers-color-scheme: dark)')

    function updateTheme(theme) {
      theme = theme ?? window.localStorage.theme ?? 'system'

      if (theme === 'dark' || (theme === 'system' && isDarkMode.matches)) {
        document.documentElement.classList.add('dark')
      } else if (theme === 'light' || (theme === 'system' && !isDarkMode.matches)) {
        document.documentElement.classList.remove('dark')
      }
      return theme
    }

    function updateThemeWithoutTransitions(theme) {
      updateTheme(theme)
      document.documentElement.classList.add('[&_*]:!transition-none')
      window.setTimeout(() => {
        document.documentElement.classList.remove('[&_*]:!transition-none')
      }, 0)
    }

    document.documentElement.setAttribute('data-theme', updateTheme())

    new MutationObserver(([{oldValue}]) => {
      let newValue = document.documentElement.getAttribute('data-theme')
      if (newValue !== oldValue) {
        try {
          window.localStorage.setItem('theme', newValue)
        } catch {
        }
        updateThemeWithoutTransitions(newValue)
      }
    }).observe(document.documentElement, {attributeFilter: ['data-theme'], attributeOldValue: true})

    isDarkMode.addEventListener('change', () => updateThemeWithoutTransitions())
  </script>

  </head>

  <body id="id-body" class="h-full w-full bg-background">
      {% block content %}{% endblock %}
  </body>
</html>

This template includes

  • SEO template tags

  • logic for rendering the correct theme.

  • Body block at the end which we override in the template below.

InertiaJS Template

text
{% extends 'base.html' %}{% load django_vite static vanty_tags %}

{% block site_assets %}
  {% vite_react_refresh %}
  {% vite_asset 'assets/js/app.jsx' %}
{% endblock %}
{% block content %}
  <div id="app" 
       class="{% if not allow_scroll %}overflow-hidden h-screen w-screen{% endif %}" 
       data-page="{{page|escape}}">
  </div>
{% endblock %}
  • {% vite_react_refresh %} - only required when using react on the frontend.

  • {% vite_asset 'assets/js/app.jsx' %} - reference to the react app entry point.

  • overflow-hidden h-screen w-screen - lock scrolling on the dashboard. You can change to handle this differently.