Learning Flask from Scratch: Template Inheritance and Variable Rendering

What is the Flask Template System?

When learning Flask, we often need to generate HTML pages from dynamic data (such as user information or database content). Flask uses the Jinja2 template engine for this purpose, which acts like an “HTML generator.” It allows us to embed Python code or variables directly into HTML, enabling dynamic page rendering.

Today, we’ll master two core skills: variable rendering (displaying Python variables on a page) and template inheritance (avoiding repetitive HTML structure), which are fundamental for building large Flask applications.

I. Variable Rendering: Making Pages “Alive”

Variable rendering refers to displaying variables from Python code (such as strings, lists, or dictionaries) on an HTML page. Jinja2 uses the {{ variable }} syntax, which is straightforward.

1. Preparation: Install Flask and Create Project Structure

First, ensure Flask is installed:

pip install flask

Create a simple project structure:

my_flask_app/
├── app.py       # Main Flask application
└── templates/   # Folder for HTML templates
    └── index.html  # Homepage template

2. View Function Passing Variables to Templates

In app.py, define a view function to handle requests and pass variables to the template:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    # Define variables of different types
    username = "小明"          # String
    age = 20                   # Number
    hobbies = ["篮球", "编程", "看书"]  # List
    user_info = {              # Dictionary
        "height": 175,
        "weight": 65,
        "city": "北京"
    }
    # Render index.html and pass variables
    return render_template('index.html', 
                          username=username, 
                          age=age, 
                          hobbies=hobbies, 
                          info=user_info)

if __name__ == '__main__':
    app.run(debug=True)  # Start Flask app in debug mode

3. Using Variables in Templates: {{ }} Syntax

In templates/index.html, use {{ variable }} to display Python variables:

<!DOCTYPE html>
<html>
<head>
    <title>{{ username }}'s Personal Page</title>
</head>
<body>
    <h1>Welcome to My Page!</h1>
    <p>My name is {{ username }}, and I'm {{ age }} years old.</p>  <!-- Display string and number -->

    <h2>My Hobbies:</h2>
    <ul>
        {% for hobby in hobbies %}  <!-- Loop through list -->
            <li>{{ hobby }}</li>
        {% endfor %}
    </ul>

    <h2>Detailed Information:</h2>
    <p>Height: {{ info.height }}cm</p>  <!-- Access dictionary by key -->
    <p>City: {{ info.city }}</p>
</body>
</html>

Running Effect: Visit http://127.0.0.1:5000/ to see:

Welcome to My Page!
My name is 小明, and I'm 20 years old.

My Hobbies:
- 篮球
- 编程
- 看书

Detailed Information:
Height: 175cm
City: 北京

4. Rendering Different Types of Variables

Jinja2 supports rendering various data types:
- List Looping: Use {% for item in list %} to iterate over lists (e.g., hobbies).
- Dictionary Access: Use {{ dict.key }} or {{ dict['key'] }} (e.g., info.city).
- Conditional Checks: Use {% if condition %} to control display logic (e.g., {% if age > 18 %}Adult{% else %}Minor{% endif %}).

II. Template Inheritance: Reusing Page Layouts

If multiple pages share the same structure (e.g., navigation bar, footer), manual HTML duplication is inefficient. Template inheritance helps unify page structure by only writing unique content.

1. Define a Base Template (base.html)

Create templates/base.html as the “skeleton” for all pages, containing common elements (navigation, footer, title):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>{% block title %}My Website{% endblock %}</title>
    <style>
        body { margin: 0; padding: 0; font-family: sans-serif; }
        nav { background: #f5f5f5; padding: 10px; }
        nav a { margin-right: 15px; text-decoration: none; color: #333; }
        .content { padding: 20px; }
        footer { text-align: center; color: #999; padding: 10px; background: #f9f9f9; }
    </style>
</head>
<body>
    <!-- Navigation Bar (Shared by all pages) -->
    <nav>
        <a href="/">Home</a>
        <a href="/about">About</a>
        <a href="/contact">Contact</a>
    </nav>

    <!-- Content Block: Filled by child templates -->
    <div class="content">
        {% block content %}{% endblock %}
    </div>

    <!-- Footer (Shared by all pages) -->
    <footer>
        © 2023 My Website - Template Inheritance Demo
    </footer>
</body>
</html>

Key Concepts:
- {% block title %}: Title placeholder for child templates to override.
- {% block content %}: Content placeholder for child templates to fill.
- {% extends "base.html" %}: Inherit from the base template (used in child templates).

2. Child Templates Inherit from Base Template

Create index.html (homepage) by extending base.html and modifying only the content block:

{% extends "base.html" %}  <!-- Inherit from base template -->

{% block title %}Home - My Website{% endblock %}  <!-- Override title block -->

{% block content %}  <!-- Override content block -->
    <h1>Welcome to the Home Page!</h1>
    <p>This is a demo of template inheritance.</p>
    <p>Current Time: {{ now }}</p>  <!-- Display Python variable -->
{% endblock %}

Create about.html (about page) similarly:

{% extends "base.html" %}

{% block title %}About Us - My Website{% endblock %}

{% block content %}
    <h1>About Us</h1>
    <p>This is a simple website built with Flask, demonstrating template inheritance and variable rendering.</p>
    <p>Our goal is to help beginners quickly master Flask development.</p>
{% endblock %}

3. Update View Functions for Child Templates

Modify app.py to support child templates:

from flask import Flask, render_template
from datetime import datetime  # Import to get current time

app = Flask(__name__)

@app.route('/')
def home():
    # Pass current time to the template
    return render_template('index.html', now=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))

@app.route('/about')
def about():
    return render_template('about.html')  # Render about.html directly

if __name__ == '__main__':
    app.run(debug=True)

4. Advantages of Template Inheritance

  • Code Reusability: Reuse navigation, footers, and other repeated elements once.
  • Consistent Styling: Maintain uniform layout and design across all pages.
  • Easy Maintenance: Update the base template to reflect changes in all child templates.

III. Complete Example: Variable Rendering + Template Inheritance

After integrating the code above, visiting different pages will show:
- Homepage: Inherits base.html with dynamic time and welcome content.
- About Page: Inherits base.html with about information.

This approach ensures clean and efficient code without repetitive HTML structures.

IV. Common Issues and Solutions

  1. Template Not Found?
    Ensure the template is in the templates folder and the path is correct (e.g., render_template('about.html')).

  2. Variable Display Error?
    Check for typos in variable names (e.g., {{ usrname }} instead of {{ username }} will show nothing).

  3. Inheritance Not Working?
    Verify {% extends "base.html" %} is at the top of the child template and the base template name is correct.

V. Summary

Today we learned:
- Variable Rendering: Use {{ variable }} to display Python variables in HTML (supports lists, dictionaries, etc.).
- Template Inheritance: Use {% extends %} and {% block %} to reuse page structures and ensure consistency.
- Project Structure: Separate app.py for logic and templates for HTML templates.

These skills are foundational for building Flask applications. Experiment with more pages (e.g., contact.html, user.html) to practice inheritance and variable rendering!

Xiaoye