Skip to main content

Flask Template Rendering

Flask Template Rendering

Flask, a lightweight Python web framework, uses the Jinja2 templating engine to render dynamic HTML content, enabling developers to create flexible and maintainable web applications. Flask template rendering involves generating HTML pages by combining static templates with dynamic data, making it ideal for data-driven applications like dashboards, forms, or machine learning (ML) interfaces using Pandas. This guide covers the mechanics of Flask template rendering, its features, best practices, and practical examples, with a focus on data-driven use cases.


01. What is Flask Template Rendering?

Template rendering in Flask is the process of generating HTML responses by passing data to Jinja2 templates. The render_template function combines a template file (typically HTML with Jinja2 syntax) with Python data to produce a dynamic webpage. This separation of presentation and logic enhances code organization and scalability.

  • Purpose: Render dynamic web content using templates and data.
  • Key Components: render_template, Jinja2 templates, and the templates folder.
  • Use Cases: Displaying user data, rendering Pandas DataFrames, creating forms, and building dashboards.

02. Setting Up Template Rendering

Flask requires templates to be stored in a templates folder in the project directory. The render_template function is used to render these templates with dynamic data.

2.1 Project Structure

project/
├── app.py
└── templates/
    ├── index.html
    └── dashboard.html

2.2 Basic Rendering Example

Example: Basic Template Rendering

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html', title='Home', greeting='Welcome to Flask!')

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

File: templates/index.html

<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
</head>
<body>
    <h1>{{ greeting }}</h1>
</body>
</html>

Output (http://127.0.0.1:5000/):

<h1>Welcome to Flask!</h1>

Explanation:

  • render_template('index.html', ...) - Renders the template with variables title and greeting.
  • {{ variable }} - Jinja2 syntax for substituting variables into the template.
  • Templates must reside in the templates folder.

03. Key Features of Template Rendering

Flask’s template rendering leverages Jinja2’s capabilities to handle dynamic content. Below are key features with examples.

3.1 Passing Variables

Variables are passed to templates via render_template and accessed using {{ variable }}.

Example: Rendering Variables

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/profile/<name>')
def profile(name):
    user = {'name': name, 'age': 25, 'city': 'New York'}
    return render_template('profile.html', user=user)

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

File: templates/profile.html

<!DOCTYPE html>
<html>
<head><title>Profile</title></head>
<body>
    <h1>{{ user.name }}'s Profile</h1>
    <p>Age: {{ user.age }}</p>
    <p>City: {{ user.city }}</p>
</body>
</html>

Output (/profile/Alice):

<h1>Alice's Profile</h1>
<p>Age: 25</p>
<p>City: New York</p>

Explanation:

  • {{ user.name }} - Accesses dictionary attributes within the template.
  • Variables can be dictionaries, lists, or other Python objects.

3.2 Rendering Lists with Loops

Jinja2’s {% for %} loop renders lists or iterables dynamically.

Example: Rendering a List

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/items')
def items():
    items = ['Apple', 'Banana', 'Orange']
    return render_template('items.html', items=items)

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

File: templates/items.html

<!DOCTYPE html>
<html>
<head><title>Items</title></head>
<body>
    <h1>Items</h1>
    <ul style="padding: 0px 0px 0px 20px; margin-top: 0px;">
    {% for item in items %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
</body>
</html>

Output (/items):

<h1>Items</h1>
<ul style="padding: 0px 0px 0px 20px; margin-top: 0px;">
    <li>Apple</li>
    <li>Banana</li>
    <li>Orange</li>
</ul>

Explanation:

  • {% for item in items %} - Iterates over the items list to create list items.

3.3 Conditional Rendering

Jinja2’s {% if %} statements enable conditional rendering based on data.

Example: Conditional Rendering

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/status/<int:score>')
def status(score):
    return render_template('status.html', score=score)

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

File: templates/status.html

<!DOCTYPE html>
<html>
<head><title>Status</title></head>
<body>
    <h1>Score: {{ score }}</h1>
    {% if score >= 60 %}
        <p>Status: Pass</p>
    {% else %}
        <p>Status: Fail</p>
    {% endif %}
</body>
</html>

Output (/status/75):

<h1>Score: 75</h1>
<p>Status: Pass</p>

Explanation:

  • {% if score >= 60 %} - Conditionally displays "Pass" or "Fail".

3.4 Template Inheritance

Template inheritance allows a base template to define a common layout, extended by child templates for specific content.

Example: Template Inheritance

File: templates/base.html

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}{% endblock %}</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <nav class="navbar navbar-light bg-light">
        <a class="navbar-brand" href="{{ url_for('home') }}">Home</a>
    </nav>
    <div class="container">
        {% block content %}{% endblock %}
    </div>
</body>
</html>

File: templates/index.html

{% extends 'base.html' %}

{% block title %}Home{% endblock %}

{% block content %}
    <h1>Welcome, {{ name }}!</h1>
{% endblock %}

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('index.html', name='Alice')

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

Output (/):

A Bootstrap-styled page with a navbar and Welcome, Alice! in the content area.

Explanation:

  • {% extends %} - Inherits the base template.
  • {% block %} - Defines sections for child templates to override.

3.5 Rendering with url_for

The url_for function generates URLs in templates, ensuring maintainable navigation.

Example: Rendering with url_for

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('home.html')

@app.route('/profile/<name>')
def profile(name):
    return render_template('profile.html', name=name)

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

File: templates/home.html

<!DOCTYPE html>
<html>
<head><title>Home</title></head>
<body>
    <h1>Home</h1>
    <a href="{{ url_for('profile', name='Alice') }}">View Alice's Profile</a>
</body>
</html>

Output (/):

A page with a link to /profile/Alice.

Explanation:

  • {{ url_for('profile', name='Alice') }} - Generates a dynamic URL for the profile route.

04. Template Rendering for Data-Driven Applications

Flask template rendering is highly effective for data-driven applications, particularly when rendering Pandas DataFrames or ML results.

Example: Rendering Pandas DataFrame

File: app.py

from flask import Flask, render_template
import pandas as pd

app = Flask(__name__)

@app.route('/dashboard')
def dashboard():
    df = pd.DataFrame({
        'Name': ['Alice', 'Bob', 'Charlie'],
        'Age': [25, 30, 35],
        'Salary': [50000, 60000, 55000]
    })
    table = df.to_html(classes='table table-striped', index=False)
    return render_template('dashboard.html', table=table, title='Dashboard')

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

File: templates/dashboard.html

<!DOCTYPE html>
<html>
<head>
    <title>{{ title }}</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h1>Data Dashboard</h1>
        {{ table | safe }}
        <a href="{{ url_for('home') }}">Back to Home</a>
    </div>
</body>
</html>

File: app.py (with home route)

from flask import Flask, render_template
import pandas as pd

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('home.html')

@app.route('/dashboard')
def dashboard():
    df = pd.DataFrame({
        'Name': ['Alice', 'Bob', 'Charlie'],
        'Age': [25, 30, 35],
        'Salary': [50000, 60000, 55000]
    })
    table = df.to_html(classes='table table-striped', index=False)
    return render_template('dashboard.html', table=table, title='Dashboard')

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

File: templates/home.html

<!DOCTYPE html>
<html>
<head><title>Home</title></head>
<body>
    <h1>Welcome</h1>
    <a href="{{ url_for('dashboard') }}">View Dashboard</a>
</body>
</html>

Output (/dashboard):

A Bootstrap-styled table displaying the DataFrame with a "Back to Home" link.

Explanation:

  • to_html - Converts the DataFrame to an HTML table with Bootstrap classes.
  • {{ table | safe }} - Renders the raw HTML safely.
  • {{ url_for('home') }} - Provides navigation back to the home page.

4.1 Rendering Dynamic Data with Loops

For more control over rendering, pass DataFrame data as a list of dictionaries and use Jinja2 loops.

Example: Custom DataFrame Rendering

File: app.py

from flask import Flask, render_template
import pandas as pd

app = Flask(__name__)

@app.route('/report')
def report():
    df = pd.DataFrame({
        'Product': ['Laptop', 'Phone', 'Tablet'],
        'Price': [1000, 600, 300]
    })
    return render_template('report.html', data=df.to_dict(orient='records'))

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

File: templates/report.html

<!DOCTYPE html>
<html>
<head>
    <title>Report</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h1>Sales Report</h1>
        <table class="table table-striped">
            <thead>
                <tr>
                    <th>Product</th>
                    <th>Price</th>
                </tr>
            </thead>
            <tbody>
                {% for row in data %}
                    <tr>
                        <td>{{ row.Product }}</td>
                        <td>${{ row.Price | float | round(2) }}</td>
                    </tr>
                {% endfor %}
            </tbody>
        </table>
    </div>
</body>
</html>

Output (/report):

A table with products and formatted prices (e.g., $1000.00).

Explanation:

  • to_dict(orient='records') - Converts DataFrame to a list of dictionaries for iteration.
  • {% for row in data %} - Builds table rows dynamically.
  • | float | round(2) - Formats prices with two decimal places.

4.2 Rendering Forms for Data Input

Templates can render forms to collect user input, often used in ML or data processing applications.

Example: Form Rendering

File: app.py

from flask import Flask, render_template, request

app = Flask(__name__)

@app.route('/predict', methods=['GET', 'POST'])
def predict():
    if request.method == 'POST':
        age = request.form.get('age')
        salary = request.form.get('salary')
        return render_template('result.html', prediction=f'Prediction for Age: {age}, Salary: {salary}')
    return render_template('form.html')

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

File: templates/form.html

<!DOCTYPE html>
<html>
<head><title>Predict</title></head>
<body>
    <h1>Enter Data</h1>
    <form method="post">
        <label>Age: <input type="number" name="age" required></label><br>
        <label>Salary: <input type="number" name="salary" required></label><br>
        <button type="submit">Predict</button>
    </form>
</body>
</html>

File: templates/result.html

<!DOCTYPE html>
<html>
<head><title>Result</title></head>
<body>
    <h1>Result</h1>
    <p>{{ prediction }}</p>
    <a href="{{ url_for('predict') }}">Try Again</a>
</body>
</html>

Output (/predict):

  • GET: Displays a form for age and salary input.
  • POST (e.g., age=25, salary=50000): Shows Prediction for Age: 25, Salary: 50000.

Explanation:

  • Form rendering - Collects user input for processing.
  • Result template - Displays dynamic results with a navigation link.

05. Best Practices for Flask Template Rendering

5.1 Recommended Practices

  • Use Template Inheritance: Create a base template for consistent layouts across pages.
  • Secure Rendering: Use | safe only for trusted HTML (e.g., Pandas to_html); escape user input to prevent XSS.
  • Optimize Data: Pass only necessary data to templates to reduce overhead.
  • Use url_for: Generate URLs dynamically for navigation links.
  • Organize Templates: Use subfolders (e.g., templates/dashboard/) for large projects.
  • Leverage Filters: Use or create custom filters for consistent formatting (e.g., currency).

5.2 Practices to Avoid

  • Avoid Untrusted HTML: Don’t use | safe with user-generated content.
  • Avoid Complex Logic: Keep business logic (e.g., data processing) in Python, not templates.
  • Avoid Hardcoding URLs: Use url_for instead of static links.

Example: Insecure Rendering

File: app.py

from flask import Flask, render_template

app = Flask(__name__)

@app.route('/comment/<comment>')
def comment(comment):
    return render_template('comment.html', comment=comment)

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

File: templates/comment.html

<!DOCTYPE html>
<html>
<head><title>Comment</title></head>
<body>
    <p>{{ comment | safe }}</p>  <!-- Insecure -->
</body>
</html>

Input: /comment/<script>alert('XSS')</script>

Output: Executes the script (XSS vulnerability).

Correct:

<p>{{ comment }}</p>  <!-- Escapes HTML -->

Output: Displays <script>alert('XSS')</script> safely.

Explanation:

  • Insecure - | safe with user input allows XSS attacks.
  • Correct - Default escaping prevents script execution.

06. Conclusion

Flask template rendering with Jinja2 enables developers to create dynamic, data-driven web applications efficiently, particularly for rendering Pandas DataFrames or ML results. Key takeaways:

  • Uses render_template to combine templates with dynamic data.
  • Supports variables, loops, conditionals, and inheritance for flexible rendering.
  • Ideal for data-driven dashboards, forms, and visualizations.
  • Follow best practices like securing output, using url_for, and organizing templates.

By mastering Flask template rendering, you can build clean, secure, and scalable web interfaces for your data-driven Flask applications!

Comments