Reusable Templates in Askama: Inheritance, Includes & Macros

Learning Objectives: By the end of this lesson, you will be able to:

  • Use template inheritance to create layouts and override content blocks
  • Include partial templates for reusable components
  • Define and use macros for repeated UI patterns

1. Welcome and Introduction (5 minutes)

Icebreaker Activity

Have you ever copied and pasted the same HTML structure across multiple pages? What if you could define it once and reuse it everywhere?

Lesson Overview

  • Duration: 75-90 minutes
  • Prerequisites: Day 1 & 2 lessons (Askama setup, control flow, loops, filters)
  • Materials Needed:
    • Rust toolchain
    • Code editor
    • Askama project with multiple templates

2. Learning Objectives and Session Outline (5 minutes)

What We’ll Cover Today:

  1. Template inheritance: layouts and blocks
  2. Includes: partials and shared components
  3. Macros: reusable template functions
  4. Hands-on practice and exercises
  5. Common pitfalls and troubleshooting

Success Criteria:

By the end of this session, you should be able to structure your templates for maximum reusability and maintainability.

3. Foundation Knowledge (15-20 minutes)

Core Concepts

Template Inheritance

Inheritance lets you define a base layout (like a master page) and override sections in child templates. Use {% extends "base.html" %} and {% block name %}...{% endblock %}.

Real-World Analogy: Like using a blueprint for a house, then customizing each room for different needs.

Why This Matters:

  • DRY (Don’t Repeat Yourself): Avoid duplicating layout code
  • Consistent look and feel across pages

Includes

Includes let you insert the contents of another template (a partial) into your current template. Use {% include "_header.html" %}.

Macros

Macros are like functions for templates. Define them with {% macro %} and call them to render repeated UI elements.

Key Terminology

  • Base Template: The parent layout file
  • Block: A named section that can be overridden
  • Partial: A small, reusable template included in others
  • Macro: A reusable template function

4. Detailed Explanation and Examples (25-30 minutes)

Understanding Reusability in Askama

Template Inheritance

<!-- templates/base.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}Default Title{% endblock %}</title>
  </head>
  <body>
    {% include "_header.html" %}
    <main>
      {% block content %}{% endblock %}
    </main>
  </body>
</html>
<!-- templates/home.html -->
{% extends "base.html" %}
{% block title %}Home Page{% endblock %}
{% block content %}
  <h1>Welcome Home!</h1>
{% endblock %}

Includes

<!-- templates/_header.html -->
<header>
  <nav>Navigation Bar</nav>
</header>
  • Included in base.html and available to all child templates

Macros

<!-- templates/macros.html -->
{% macro button(label: &str, url: &str) %}
  <a href="{{ url }}" class="btn">{{ label }}</a>
{% endmacro %}
<!-- templates/home.html -->
{% import "macros.html" as macros %}
...
{{ macros::button("Click Me", "/action") }}

Overriding Blocks and Using super()

{% block content %}
  {{ super() }}
  <p>Extra content below the parent block.</p>
{% endblock %}

Common Misconceptions

  1. Misconception: “Includes and inheritance are the same.” Reality: Inheritance is for layouts; includes are for partials/components.
  2. Misconception: “Macros can only access their arguments.” Reality: Macros inherit variables from their call site, but explicit arguments make dependencies easier to see and reuse.

5. Live Coding Demonstration (20-25 minutes)

Example 1: Base and Child Templates

// main.rs
use askama::Template;
#[derive(Template)]
#[template(path = "home.html")]
struct HomeTemplate {
    user: String,
}

fn main() {
    let template = HomeTemplate { user: "Alice".to_string() };
    println!("{}", template.render().unwrap());
}
<!-- templates/home.html -->
{% extends "base.html" %}
{% block title %}Home{% endblock %}
{% block content %}
  <h1>Hello, {{ user }}!</h1>
{% endblock %}

Example 2: Including a Partial

<!-- templates/_header.html -->
<header>
  <nav>Welcome, {{ user }} | <a href="/logout">Logout</a></nav>
</header>
<!-- In the base.html from Example 1, use this inside <body>: -->
{% include "_header.html" %}

Example 3: Macros for Reusable UI

<!-- templates/macros.html -->
{% macro badge(text: &str, kind: &str) %}
  <span class="badge badge-{{ kind }}">{{ text }}</span>
{% endmacro %}
<!-- In templates/home.html, import at top level alongside extends, then call inside content block: -->
{% import "macros.html" as macros %}
{% block content %}
{{ macros::badge("New", "success") }}
{% endblock %}

Debugging Demonstration

Show common errors and how to fix them:

<!-- Valid, but renders the base block's default content instead of a custom page: -->
{% extends "base.html" %}
{# No content block defined #}

<!-- Corrected: override the block -->
{% block content %}...{% endblock %}

6. Hands-On Practice (30-40 minutes)

Exercise 1: Basic Practice (10 minutes)

Objective: Create a base template and a child template with a custom title and content.

Instructions:

  1. Make base.html with title and content blocks
  2. Make about.html that extends base.html and overrides both blocks
  3. Render AboutTemplate in Rust

Starter Code:

#[derive(Template)]
#[template(path = "about.html")]
struct AboutTemplate;

Solution:

fn main() {
    let t = AboutTemplate;
    println!("{}", t.render().unwrap());
}

Exercise 2: Intermediate Challenge (15 minutes)

Objective: Use an include for a shared header and a macro for a button.

Requirements:

  • Add _header.html and include it in base.html
  • Define a macro for a button in macros.html and use it in a child template
  • Pass different labels/URLs to the macro

Hints:

  • Use {% import "macros.html" as macros %}
  • Call with {{ macros::button("Label", "/url") }}

Exercise 3: Creative Application (15 minutes)

Objective: Build a reusable list macro and use it in multiple templates.

Challenge:

  • Write a macro that takes a list and renders it as an HTML list
  • Use it in both home.html and about.html

Extension Ideas:

  • Add parameters for list style (ordered/unordered)
  • Add a macro for a styled alert box

7. Common Pitfalls and Troubleshooting (10 minutes)

Frequent Mistakes

  1. Problem: Seeing the base block’s default content Cause: Child template doesn’t override the block Solution: Override blocks where you need different content (not a compile error)
  2. Problem: Macro argument mismatch Cause: Wrong number/type of arguments Solution: Check macro signature and usage

Debugging Tips

  • Use clear block and macro names
  • Read error messages for missing blocks or includes
  • Test includes and macros in isolation first

8. Best Practices and Professional Tips (5 minutes)

Industry Standards

  • Use inheritance for layouts, includes for partials, macros for repeated UI
  • Keep templates organized in folders
  • Document macro signatures and usage

Next Steps in Your Learning Journey

  • Explore custom filters and advanced macros
  • Integrate Askama with a web framework
  • Read the Askama Book for more on reusability

9. Summary and Review (5 minutes)

Key Takeaways

  1. Inheritance, includes, and macros make templates DRY and maintainable
  2. Use blocks for layout, includes for components, macros for repeated UI
  3. Always test and document reusable template parts

Quick Review Questions

  1. How do you override a block in a child template?
  2. What’s the difference between an include and inheritance?
  3. How do you define and use a macro in Askama?

For Instructors

Teaching Tips

  • Show real-world layout and component reuse
  • Encourage students to refactor repeated code into blocks/macros
  • Use live coding to demonstrate inheritance and includes

Assessment Ideas

  • Ask students to build a layout with at least two child templates
  • Review macro usage and argument passing
  • Peer review: swap templates and check for DRYness

Adaptation Notes

  • For beginners: provide base/child template scaffolding
  • For advanced students: challenge with nested blocks and macro imports
  • Online: use screen sharing for template structure walkthroughs