除了开发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...

相关推荐
前进的李工4 小时前
飞书企业知识库设计+后端高频八股
数据库·redis·后端·mysql·性能优化·飞书·rag
TechWayfarer4 小时前
PHP漏洞被利用,怎么揪出攻击IP?
开发语言·python·tcp/ip·网络安全·php
2601_967980115 小时前
Python列表操作方法详解
python·数据类型·修改·列表操作·功能汇总
金銀銅鐵5 小时前
[Java] 展示增删元素时 LinkedList 的内部变化
java·后端·ai编程
Patrick在香港5 小时前
台风在变少,来香港的没有
python·数据分析·香港·开放数据·热带气旋
qq_406981035 小时前
大白话rust系列09 函数调用两次有什么错?
开发语言·python·rust
小林ixn6 小时前
FastAPI + LangChain 实战:从 0 到 1 打造高性能 AI 后端服务
人工智能·langchain·fastapi
benchmark_cc6 小时前
QuantDash 安装成功后,如何验证 Python 环境可以正常导入 SDK?
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
武子康6 小时前
Vercel Cache Reason:相同 MISS,怎样决定下一步查什么
人工智能·后端·agent
杨文说AI与数字化7 小时前
把模型依赖做成可替换的组件:三层适配 + 一套回归评估
后端