Flask, Routing, and Templates
Build server side apps with Flask, manage routes, and render Jinja templates effectively.
Content
Template inheritance
Versions:
Watch & Learn
AI-discovered learning video
Sign in to watch the learning video for this topic.
Template Inheritance in Flask (Jinja2): The DRY Layout Magic
"If your HTML repeats like a bad joke, template inheritance is the mic drop."
You're already comfortable with Jinja2 syntax and how Flask handles requests and responses — nice groundwork. Now we upgrade your front-end life from copy-paste chaos to elegant, maintainable layouts using template inheritance. Think of it as the class hierarchy for your HTML: one superstar base template, many specialized children that only change what they need to.
What is template inheritance? (Short elevator pitch)
Template inheritance lets child templates extend a base template and override named blocks. The base supplies the common layout (header, nav, footer), children fill in the content. Result: DRY (Don't Repeat Yourself) HTML across your app.
Why this matters:
- You avoid repeating site chrome (navbars, footers, CSS includes).
- Changes to site-wide layout happen in one file — one edit, everywhere fixed.
- Templates stay readable and focused.
This builds naturally on your knowledge of Jinja2 syntax (blocks, variables, control structures) and on how Flask's render_template passes context from routes (you learned that with request/response handling).
Anatomy: base.html and a child
base.html (the master layout)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}My Site{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='styles.css') }}">
{% block head %}{% endblock %}
</head>
<body>
<header>
<h1>My Site</h1>
{% include 'nav.html' %}
</header>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<small>© {{ current_year }}</small>
</footer>
{% block scripts %}{% endblock %}
</body>
</html>
Key parts:
- {% block name %}...{% endblock %} — placeholders the children can override.
- {{ url_for(...) }} — remember from routing: never hard-code paths; use url_for so links stay robust when routes change.
- {% include 'nav.html' %} — small partials for repetition inside the base.
child template: index.html
{% extends 'base.html' %}
{% block title %}Home — My Site{% endblock %}
{% block content %}
<h2>Welcome!</h2>
<p>This content is specific to the home page.</p>
{% endblock %}
Child templates only override what they need — amazing.
A few powerful tricks
super()
You can use {{ super() }} to append to the parent's block rather than replace it.
{% block scripts %}
{{ super() }}
<script src="/extra.js"></script>
{% endblock %}
Good when base defines shared scripts but a page needs an extra one.
include vs. macro vs. extend
- include: insert a partial (like nav or a card). Good for small reusable chunks.
- macro: like a function inside templates — perfect for rendering repeated UI with parameters.
- extends: the inheritance link to the base template.
Use macros for complex repeated markup with arguments:
{% macro user_card(user) %}
<div class="card">
<h3>{{ user.name }}</h3>
<p>{{ user.bio }}</p>
</div>
{% endmacro %}
{{ user_card(current_user) }}
Template order and folder structure
- Keep templates under your app's templates/ directory.
- For Blueprints, use a blueprint-specific templates folder (Flask finds them).
- Naming convention: base.html, _nav.html (leading underscore for partials — a convention, not required).
Security and context notes (tiny but important)
- Jinja2 auto-escapes variables by default to prevent XSS. Use |safe only when you are absolutely sure the string is safe.
- Use Flask's render_template('x.html', var=value) to pass variables — you already use this pattern when handling requests.
- You can access request and session inside templates if you pass them or register them as template globals; but keep heavy logic in Python (controllers), not templates.
Micro-explanation: templates are for presentation. Python functions are for business logic. Keep that contract or future-you will be sad.
Example Flask route wiring (small reminder)
from flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html', current_year=datetime.now().year)
Because you pass current_year from the view, the base can render the footer year without each child worrying about it.
Debugging tips & common pitfalls
- If a child shows the base content instead of its override, check block names: they must match exactly.
- If templates aren’t found, confirm template directory or blueprint setup.
- Don't put heavy Python logic in templates — keep them declarative.
- For long pages, break sections into includes and macros to remain readable.
When to use inheritance (and when not)
Use inheritance when pages share a common layout (most websites). Avoid it for tiny one-off HTML files or emails that drastically differ — though even emails often benefit from a base template.
Quick checklist (so you don’t forget things during the next panic fix)
- Create base.html with header, footer, and named blocks
- Use {% extends 'base.html' %} in child templates
- Prefer url_for for static files and routes
- Use include for small partials and macros for reusable components
- Keep logic in Python routes; templates display
- Use super() to add to base blocks instead of replacing them
Key takeaways
- Template inheritance = maintainable layout + less duplicated HTML.
- Blocks define replaceable areas; extends links to base; include and macros are helpers.
- Use url_for and Flask's render_template to keep links and context robust (you already learned this when working with requests/responses).
- Keep templates focused on presentation; apply your Python fundamentals for logic and data.
Final thought: Treat base.html like the stage manager of a play — it sets the scene while the child templates bring the lines. One stage manager, many actors, no chaos.
Happy templating. Break the repetition, not the Internet.
Comments (0)
Please sign in to leave a comment.
No comments yet. Be the first to comment!