🗃 Backend
Multi-Level Inheritance in HTML with Jinja2
date
Jun 21, 2023
slug
multi-level-inheritance-in-html-with-jinja2
author
status
Public
tags
Flask
Python
Jinja2
HTML
summary
type
Post
thumbnail
category
🗃 Backend
updatedAt
Jun 21, 2023 08:13 AM
📜 Table of Contents
📖 Inheritance in Jinja2: extends(), super()
In the context of Jinja2,
{% extends %}
and {{ super() }}
play crucial roles in achieving template inheritance.{% extends "base.html" %}
is used to specify a base template that the current template will inherit from. All the HTML structure and blocks from the base template will be included in the current template, unless they are overridden.
{{ super() }}
is used within overridden blocks in the child template to include content from the corresponding block in the parent template. This allows you to build upon the existing content in a block, instead of completely replacing it.
These two features together give you a lot of flexibility in organizing your HTML templates. You can create a common structure with your base template and then customize it with child templates, minimizing code repetition and enhancing maintainability.
✅ Key Function #1: extends()
In Jinja2,
{% extends %}
is a tag that is used to specify that a template should inherit from another template. This is the basis for template inheritance, a powerful feature that allows you to build a base "skeleton" template that contains all the common elements of your site and defines blocks that child templates can override.Here is how it works:
- In your base template, you define blocks with
{% block blockname %}
and{% endblock %}
tags. These blocks can be overridden by child templates.
- To create a child template that extends the base template, you use the
{% extends "base.html" %}
tag at the top of the child template. Replace"base.html"
with the path to your base template.
- In the child template, you can define content for the blocks you have declared in the base template.
Here is a basic example:
<html> <head> <title>{% block title %}Default Title{% endblock %}</title> </head> <body> <div id="content">{% block content %}Default content{% endblock %}</div> </body> </html>
{% extends "base.html" %} {% block title %} Child Page {% endblock %} {% block content %} <p>This is content for the child page.</p> {% endblock %}
In this example,
child.html
extends base.html
and overrides the title
and content
blocks. When you render child.html
, the resulting HTML will be:<html> <head> <title>Child Page</title> </head> <body> <div id="content"> <p>This is content for the child page.</p> </div> </body> </html>
If a block is not defined in the child template, the content from the parent template will be used. This allows you to provide default content in your base template.
It's important to note that
{% extends %}
must be the first tag in the template. Also, you can only extend one template at a time in Jinja2 - you cannot extend multiple templates in the same child template. If you need to extend multiple templates, you will need to create a chain of inheritance.✅ Key Function #2: super()
The
super()
function in Jinja2 works in tandem with the {% extends %}
statement and {% block %}
tags to provide a more flexible way to override blocks in the parent template.When you use
{% extends "base.html" %}
in a child template, you're specifying that this template should inherit the structure of base.html
. Then, within this child template, you can use {% block blockname %}
and {% endblock %}
to replace or extend the blocks defined in the parent template.If you want to replace the entire content of a block from the parent template, you simply define the block in your child template and put the new content within this block.
However, there are times when you want to keep some or all of the content of the parent block, and just add some extra content or make minor changes. This is where the
super()
function comes in.The
super()
function, when called inside a {% block %}
in the child template, will insert the content from the parent template's corresponding block.Let's continue the previous example:
<html> <head> <title>{% block title %}Default Title{% endblock %}</title> </head> <body> <div id="content">{% block content %}Default content{% endblock %}</div> </body> </html>
{% extends "base.html" %} {% block title %} Child Page {% endblock %} {% block content %} {{ super() }} <p>This is additional content for the child page.</p> {% endblock %}
In
child.html
, we call super()
within the content
block. When you render child.html
, the resulting HTML will be:<html> <head> <title>Child Page</title> </head> <body> <div id="content"> Default content <p>This is additional content for the child page.</p> </div> </body> </html>
As you can see,
super()
has included the original content ("Default content") from the content
block of base.html
and then appended the new content from the child.html
.In essence,
super()
allows you to build upon the content of blocks from your base template, rather than entirely replacing them.📖 Multi-Level Inheritance in Jinja2
Jinja2, which is used in Flask, does not support multiple inheritance in the form of extending from more than one parent template at the same time. It does, however, support multi-level inheritance which means you can have a chain of templates extending each other.
✅ Principle
The principle of multi-level inheritance in Jinja2 is similar to the principle of inheritance in object-oriented programming. The key idea is that you have a hierarchy of templates, with a base template at the top and potentially many levels of child templates beneath it. Each template in the hierarchy can override blocks from its parent template.
Here are the key points of multi-level inheritance in Jinja2:
- Block Overriding: Each child template can override the blocks from its parent. The overridden block in the child template replaces the block from the parent template when the child template is rendered. If the
{{ super() }}
function is used in an overridden block, it will include the content from the parent's block.
- Block Filling: If a block is not overridden in a child template, the content from the parent template's block will be used.
- Order of Precedence: In multi-level inheritance, the closest level of inheritance takes precedence. That means if a grandchild, child, and base template all define the same block, the content from the grandchild's block will be used because it's the most immediate level of inheritance. However, if the grandchild uses the
{{ super() }}
function in the block, it will include the content from its parent (the child template) before its own content.
For instance, let's assume you have three templates:
base.html
, child.html
, and grandchild.html
.- Base Template: This is the top-level template that provides a common structure for the other templates. It defines blocks that can be filled in or overridden by child templates.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}Base Title{% endblock %}</title> </head> <body> <header>{% block header %}Base Header{% endblock %}</header> <main>{% block content %}Base Content{% endblock %}</main> <footer>{% block footer %}Base Footer{% endblock %}</footer> </body> </html>
- Child Templates: These templates extend the base template using
{% extends "base.html" %}
(replace"base.html"
with your base template's filename). They can fill in or override blocks from the base template.
{% extends "base.html" %} {% block title %}Child Title{% endblock %} {% block header %}Child Header{% endblock %} {% block content %}Child Content{% endblock %} {% block footer %}Child Footer{% endblock %}
- Grandchild Templates: These templates extend a child template. They can fill in or override blocks from their immediate parent (the child template), and by extension, they can also override blocks from the base template.
{% extends "child.html" %} {% block title %}Grandchild Title{% endblock %} {% block header %}Grandchild Header{% endblock %} {% block content %} <p>{{ super() }}</p> <p>Grandchild Additional Content</p> {% endblock %} {% block footer %}Grandchild Footer{% endblock %}
When you render
grandchild.html
, it will inherit properties from child.html
, which in turn inherits from base.html
. This is the closest concept to multiple inheritance in Jinja2.You can override blocks from the parent template, and use
{{ super() }}
if you want to include the content of the parent block. In this case, when you render grandchild.html
, the content block will first include the content from child.html
's content block (i.e., "Child Content"), and then append "Grandchild Additional Content".📝 Summary
This post explains how to use Jinja2 to achieve multi-level inheritance in HTML templates. The extends() and super() functions are crucial for template inheritance, and allow for a base template to be customized by child templates. Multi-level inheritance is supported in Jinja2, enabling templates to inherit from a chain of templates. This feature helps minimize code repetition and enhances maintainability, but may require more initial setup time and can be confusing for beginners.
🐣 Pros
- Template inheritance allows for a common structure to be established in a base template, minimizing code repetition.
- Child templates can override blocks from the base template, allowing for customization.
- The super() function enables child templates to build upon the content of parent templates, rather than entirely replacing them.
- Multi-level inheritance in Jinja2 allows for a chain of templates to be established, enabling templates to inherit from each other.
- Using inheritance can enhance code maintainability and organization.
🐷 Cons
- Extensive use of template inheritance can make code more complex and harder to debug.
- The use of super() can make it difficult to understand the source of content within a block.
- Multi-level inheritance can be confusing for beginners and require more initial setup time.
- Jinja2 does not support multiple inheritance in the form of extending from more than one parent template at the same time.
- Inheritance can lead to overly complex code if not used carefully.