Jinja2 template
In this chapter, you will learn to configure the Jinja2 template engine in FastAPI, using static files and template inheritance to build complete HTML pages.
FastAPI's two rendering modes
FastAPI returns JSON by default (suitable for APIs), but it can also return HTML (suitable for SSR).
The two modes can coexist—the same project can provide both a JSON API and render web pages.
Mount static files
Static files (CSS, JS, images) are handled throughStaticFilesMount to the specified path.
Example
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
# Mount the static/ directory to the /static path
# Access /static/css/style.css → actually reads static/css/style.css
app.mount("/static", StaticFiles(directory="static"), name="static")
Referencing static files in templates:
Example
<img src="/static/images/logo.png">
Configure Jinja2 templates
Example
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 template directory
templates = Jinja2Templates(directory="templates")
@app.get("/")
def index(request: Request): # Note: The template route must receive a Request parameter.
"""Blog home page"""
return templates.TemplateResponse(
"index.html", # Template filename
{ # context data
"request": request, # request must be passed in (Jinja2Templates requirement)
"title": "EXAMPLE blog"
}
)
FastAPI's template rendering has two key differences from Flask: 1. The view function must receive
request: Requestparameter; 2.requestMust be passed to the template as context. If request is omitted, the url_for function in the template will fail.
Create the base.html parent template
Example
<!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 %}EXAMPLE Blog{% endblock %}</title>
<link rel="stylesheet" href="/static/css/style.css">
{% block extra_head %}{% endblock %}
</head>
<body>
<header class="navbar">
<a href="/" class="logo">EXAMPLE 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 EXAMPLE Blog. Powered by FastAPI.</p>
</footer>
</body>
</html>
Create the index.html child template
Example
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">Latest Articles</h2>
<p>The article list will be displayed in later chapters.</p>
{% endblock %}
url_for() in FastAPI Templates
Similar to Flask, FastAPI also supportsurl_for(), but you need to name the route first.
Example
def post_detail(request: Request, post_id: int):
return templates.TemplateResponse("post_detail.html",
{"request": request, ...})
Example
<a href="{{ url_for('post_detail', post_id=3) }}">Article 3</a>
Create basic CSS styles
Example
* { 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 frontend rendering configuration in FastAPI: StaticFiles for mounting static resources, Jinja2Templates for configuring the template directory, TemplateResponse for returning HTML, and key differences from Flask in template rendering (the Request parameter must be passed in).
other extensions