TUTORIALBackendFETCHED
Jinja2 模板
Jinja2 模板 本章你将学会在 FastAPI 中配置 Jinja2 模板引擎,用静态文件和模板继承构建完整的 HTML 页面。 FastAPI 的两种渲染模式 FastAPI 默认返回 JSON(适合 API),但也能返回 HTML(适合 SSR)。 两种模式可以共存——同一个项目既可以提供 JSON API,也可以渲染网页。 挂载静态文件 静态文件(CSS、JS、图片)通过 StaticFiles 挂载到指定路径。 ..
Updated 7/16/2026
Tutorial detail pages default to noindex.
Jinja2 模板
本章你将学会在 FastAPI 中配置 Jinja2 模板引擎,用静态文件和模板继承构建完整的 HTML 页面。
FastAPI 的两种渲染模式
FastAPI 默认返回 JSON(适合 API),但也能返回 HTML(适合 SSR)。
两种模式可以共存——同一个项目既可以提供 JSON API,也可以渲染网页。
挂载静态文件
静态文件(CSS、JS、图片)通过 StaticFiles 挂载到指定路径。
实例
# 文件路径:main.py
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
# 将 static/ 目录挂载到 /static 路径
# 访问 /static/css/style.css → 实际读取 static/css/style.css
app.mount("/static", StaticFiles(directory="static"), name="static")
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
app = FastAPI()
# 将 static/ 目录挂载到 /static 路径
# 访问 /static/css/style.css → 实际读取 static/css/style.css
app.mount("/static", StaticFiles(directory="static"), name="static")
模板中引用静态文件:
实例
<link rel="stylesheet" href="/static/css/style.css">
<img src="/static/images/logo.png">
<img src="/static/images/logo.png">
配置 Jinja2 模板
实例
# 文件路径: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")
# 指定模板目录
templates = Jinja2Templates(directory="templates")
@app.get("/")
def index(request: Request): # 注意:模板路由必须接收 Request 参数
"""博客首页"""
return templates.TemplateResponse(
"index.html", # 模板文件名
{ # context 数据
"request": request, # request 必须传入(Jinja2Templates 要求)
"title": "RUNOOB 博客"
}
)
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")
# 指定模板目录
templates = Jinja2Templates(directory="templates")
@app.get("/")
def index(request: Request): # 注意:模板路由必须接收 Request 参数
"""博客首页"""
return templates.TemplateResponse(
"index.html", # 模板文件名
{ # context 数据
"request": request, # request 必须传入(Jinja2Templates 要求)
"title": "RUNOOB 博客"
}
)
FastAPI 的模板渲染与 Flask 有两个关键区别:1. 视图函数必须接收
request: Request参数;2.request必须作为 context 传给模板。如果漏传 request,模板中的 url_for 功能会失效。
创建 base.html 父模板
实例
<!-- 文件路径: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 %}RUNOOB 博客{% endblock %}</title>
<link rel="stylesheet" href="/static/css/style.css">
{% block extra_head %}{% endblock %}
</head>
<body>
<header class="navbar">
<a href="/" class="logo">RUNOOB 博客(FastAPI)</a>
<nav>
<a href="/">首页</a>
<a href="#">关于</a>
</nav>
</header>
<main class="container">
{% block content %}{% endblock %}
</main>
<footer class="footer">
<p>© 2024 RUNOOB 博客. Powered by FastAPI.</p>
</footer>
</body>
</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 %}RUNOOB 博客{% endblock %}</title>
<link rel="stylesheet" href="/static/css/style.css">
{% block extra_head %}{% endblock %}
</head>
<body>
<header class="navbar">
<a href="/" class="logo">RUNOOB 博客(FastAPI)</a>
<nav>
<a href="/">首页</a>
<a href="#">关于</a>
</nav>
</header>
<main class="container">
{% block content %}{% endblock %}
</main>
<footer class="footer">
<p>© 2024 RUNOOB 博客. Powered by FastAPI.</p>
</footer>
</body>
</html>
创建 index.html 子模板
实例
<!-- 文件路径:templates/index.html -->
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">最新文章</h2>
<p>文章列表将在后续章节展示。</p>
{% endblock %}
{% extends 'base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">最新文章</h2>
<p>文章列表将在后续章节展示。</p>
{% endblock %}
FastAPI 模板中的 url_for()
与 Flask 类似,FastAPI 也支持 url_for(),但需要先给路由起名字。
实例
@app.get("/post/{post_id}", name="post_detail") # name= 给路由命名
def post_detail(request: Request, post_id: int):
return templates.TemplateResponse("post_detail.html",
{"request": request, ...})
def post_detail(request: Request, post_id: int):
return templates.TemplateResponse("post_detail.html",
{"request": request, ...})
实例
<!-- 模板中引用 -->
<a href="{{ url_for('post_detail', post_id=3) }}">文章 3</a>
<a href="{{ url_for('post_detail', post_id=3) }}">文章 3</a>
创建基础 CSS 样式
实例
/* 文件路径: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; }
* { 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; }
本章小结
本章你学会了 FastAPI 中的前端渲染配置:StaticFiles 挂载静态资源、Jinja2Templates 配置模板目录、TemplateResponse 返回 HTML、与 Flask 在模板渲染上的关键差异(Request 参数必须传入)。