Jinja2 Templates
In this chapter, you will learn how to configure the Jinja2 template engine in FastAPI and build complete HTML pages using static files and template inheritance.
Two Rendering Modes in FastAPI
By default, FastAPI returns JSON (suitable for APIs), but it can also return HTML (suitable for SSR).
Both modes can coexist β the same project can provide JSON APIs and render web pages simultaneously.
Mounting Static Files
Static files (CSS, JS, images) are mounted to a specified path using StaticFiles.
Example
# File path: main.py
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
# Mount the "static/" directory to the "/static" path
# Accessing /static/css/style.css β actually reads static/css/style.css
app.mount("/static", StaticFiles(directory="static"), name="static")
Referencing static files in templates:
Example
<link rel="stylesheet" href="/static/css/style.css">
<img src="/static/images/logo.png">
Configuring Jinja2 Templates
Example
# File path: main.py
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
# Specify the templates directory
templates = Jinja2Templates(directory="templates")
@app.get("/")
def index(request: Request): # Note: Template routes must receive a Request parameter
"""Blog homepage"""
return templates.TemplateResponse(
"index.html", # Template filename
{# context data #}
{
"request": request, # request must be passed (required by Jinja2Templates)
"title": "TUTORIAL Blog"
}
)
FastAPIβs template rendering differs from Flask in two key ways: 1) The view function must accept the
request: Requestparameter; 2)requestmust be passed to the template as context. Ifrequestis omitted, theurl_for()functionality in templates will fail.
Creating the base.html Parent Template
Example
<!-- File path: templates/base.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}TUTORIAL Blog{% endblock %}</title>
<link rel="stylesheet" href="/static/css/style.css">
{% block extra_head %}{% endblock %}
</head>
<body>
<header class="navbar">
<a href="/" class="logo">TUTORIAL Blog (FastAPI)</a>
<nav>
<a href="/">Home</a>
<a href="#">About</a>
</nav>
</header>
<main class="container">
{% block content %}{% endblock %}
</main>
<footer class="footer">
<p>Β© 2024 TUTORIAL Blog. Powered by FastAPI.</p>
</footer>
</body>
</html>
Creating the index.html Child Template
Example
<!-- File path: templates/index.html -->
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">Latest Articles</h2>
<p>Article list will be shown in later chapters.</p>
{% endblock %}
Using url_for() in FastAPI Templates
Similar to Flask, FastAPI supports url_for(), but routes must be explicitly named first.
Example
@app.get("/post/{post_id}", name="post_detail") # name= assigns a name to the route
def post_detail(request: Request, post_id: int):
return templates.TemplateResponse("post_detail.html",
{"request": request, ...})
Example
<!-- Reference in template -->
<a href="{{ url_for('post_detail', post_id=3) }}">Article 3</a>
Creating Basic CSS Styles
Example
/* File path: static/css/style.css */
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f5f5f5;
color: #333;
}
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 40px;
background: #fff;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}
.navbar .logo {
font-size: 22px;
font-weight: bold;
color: #009688;
text-decoration: none;
}
.navbar nav a {
margin-left: 20px;
text-decoration: none;
color: #333;
}
.container {
max-width: 960px;
margin: 40px auto;
padding: 0 20px;
}
.footer {
text-align: center;
padding: 20px;
color: #999;
border-top: 1px solid #eee;
}
.section-title {
font-size: 24px;
margin-bottom: 20px;
}
Chapter Summary
In this chapter, you learned how to configure frontend rendering in FastAPI: mounting static resources with StaticFiles, configuring template directories with Jinja2Templates, returning HTML with TemplateResponse, and the key differences from Flask in template rendering (the Request parameter must be passed).
YouTip