除了开发api,FastAPI其实也可以配合jinja2模板写页面

在很多人眼里,FastAPI 天生就是为了写前后端分离的 JSON 接口而生的。但凡事总有例外,在构建管理后台、博客系统或者轻量级工具时,比起折腾复杂的前端工程化框架,直接在服务端把 HTML 页面拼装好扔给浏览器,往往更简单、更痛快。

FastAPI 与 Jinja2 的结合,正是为了解决这一诉求。它既保留了 Python 异步框架的风驰电掣,又继承了经典的服务端渲染体验 。


什么是模板渲染,不妨把它看作填字游戏

如果把服务端渲染想象成一个具体的场景,它非常像小学生写请假条的填空模版

你在模版里留好空白,比如 ___同学因为___原因需要请假___天。当有学生发起申请时,服务端程序把具体的名字、原因和天数填进空白处,整合成一张完整的请假条,再交给班主任。

在 Web 世界里,Jinja2 就是那个负责填空的模板引擎,HTML 文件是模版,FastAPI 则是那个接收请求、查询数据库并把具体数据喂给模板的指挥官 。

flowchart LR Browser([用户浏览器]) -->|1. 发送 HTTP 请求| FastAPI[FastAPI 路由处理] FastAPI -->|2. 查询数据并准备上下文 Context| Context[(数据字典 Context)] FastAPI -->|3. 调用模版文件 item.html| Template[Jinja2 模板文件] Context & Template --> Jinja2Engine[Jinja2 渲染引擎] Jinja2Engine -->|4. 生成完整 HTML| Response[HTMLResponse] Response -->|5. 返回渲染好的网页| Browser

整个工作流清晰明了,浏览器发出请求,FastAPI 拿到参数后组装成一个数据字典,Jinja2 负责把数据嵌入到 HTML 中,最后把纯文本的 HTML 网页原样送回浏览器解析呈现 。


搭建基底,从目录结构与环境准备开始

要让这套体系转起来,第一步是准备好渲染引擎。FastAPI 并没有将 Jinja2 硬编码进核心库,而是借助其底层的 Starlette 框架进行集成,因此需要手动安装依赖包 。

在终端执行环境安装,

bash 复制代码
pip install jinja2

接下来是推荐的标准工程目录结构。将页面模版与静态资源(如 CSS 样式表、JavaScript 脚本和图片)分门别类放置,

text 复制代码
my_project/
├── main.py
├── static/
│   └── styles.css
└── templates/
    └── item.html

核心运作代码剖析

服务端渲染的代码非常紧凑,主要分为配置模板引擎、挂载静态资源、定义路由三个关键动作。

main.py 中,编写如下代码,

python 复制代码
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
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("/items/{id}", response_class=HTMLResponse)
async def read_item(request: Request, id: str):
    # 业务数据
    item_data = {"id": id, "name": "机械键盘", "price": 499}
    
    # 渲染并返回 HTML 页面
    return templates.TemplateResponse(
        request=request, 
        name="item.html", 
        context={"item": item_data}
    )

这段代码藏着两个极为关键的细节。

路由函数的参数列表中必须明确声明 request: Request。很多人初学时容易忽略它,但在模板体系中,Jinja2 需要通过 request 对象来识别当前的请求上下文,包括提取 Cookies、请求头以及后续生成静态资源的绝对链接 。

在较新的 FastAPI 与 Starlette 版本中,templates.TemplateResponse 推荐将 request 作为显式参数传入,也可以将其放置在 context 字典中,但显式传递 request=request 更加直观且符合现代类型推导标准。


编写 Jinja2 模板与静态资源配合

来看对应的 templates/item.html 模板文件。Jinja2 允许开发者使用双大括号 {{ }} 输出变量,使用 {% %} 编写循环和判断逻辑。

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>商品详情 - {{ item.name }}</title>
    <!-- 使用 url_for 动态反向解析静态文件路径 -->
    <link href="{{ url_for('static', path='/styles.css') }}" rel="stylesheet">
</head>
<body>
    <div class="card">
        <h1>商品 ID, {{ item.id }}</h1>
        <p>名称, <strong>{{ item.name }}</strong></p>
        <p>价格, ¥{{ item.price }}</p>
        
        {% if item.price > 300 %}
            <span class="badge">包邮商品</span>
        {% else %}
            <span>运费 10 元</span>
        {% endif %}
    </div>
</body>
</html>

这里的亮点在于 {{ url_for('static', path='/styles.css') }}。它并不是简单地写死相对路径,而是利用 FastAPI 注册的路由名称 static 动态生成正确的资源 URL。这意味着即使未来将静态资源迁移到子路径或者特定反向代理下,整个系统的链接结构也不会轻易失效 。


服务端渲染的适用边界

把 FastAPI 和 Jinja2 绑在一起用,并不是要开历史倒车去全盘否定前端现代化单页应用(SPA)。

当你的项目主要用于内部数据看板、简易管理系统、SEO 要求极高且交互简单的内容展示站时,这套方案省去了 Vue 或 React 的打包配置、跨域设置以及接口联调成本。用最地道的 Python 代码,搭配极其直观的 HTML 模板,几十分钟就能搭建出稳定健壮的 Web 服务。


参考资料

FastAPI 官方文档 - 模板使用指南, fastapi.tiangolo.com/zh/advanced...

相关推荐
belldeep1 小时前
python:Selenium 4.47 编码新的写法
python·selenium
OPEN-F1 小时前
Python进阶教程:项目工程化与虚拟环境
开发语言·python
newerp1 小时前
Redis 操作与缓存策略
后端·程序员·go
newerp1 小时前
GORM ORM 基础
后端·程序员·go
小岛前端1 小时前
AI Skills 已经封神,但新的问题却越来越严重!
前端·后端·github
OPEN-F1 小时前
Python进阶教程:自动化办公实战
python·c#·自动化
拖孩1 小时前
一个人 + AI 做的小程序,上线 15 天赚了 10 块 5
前端·后端·微信小程序
newerp1 小时前
CRUD 操作与预处理语句
后端·程序员·go
minglie11 小时前
python串口的stream数据mock
python