FastAPI 完全可以接入模板引擎来开发传统网站!虽然 FastAPI 以构建高性能 API 著称,但它基于 Starlette 框架,天然支持模板渲染和静态文件托管。
模板引擎选型
引擎 | 特点 | 安装命令 |
Jinja2 | 语法简洁,广泛使用 | pip install jinja2 |
Mako | 高性能,支持嵌入 Python | pip install mako |
Chameleon | XML 风格,适合复杂模板 | pip install chameleon |
推荐使用 Jinja2(与 FastAPI 集成最方便)
Jinja2 集成步骤
项目结构
. ├── main.py ├── templates/ │ ├── index.html │ └── includes/ │ └── header.html └── static/ ├── css/ └── js/
安装依赖
pip install jinja2
配置模板引擎
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")
基础模板渲染
创建模板文件 templates/index.html
<!DOCTYPE html> <html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_for('static', path='/css/style.css') }}"> </head> <body> <h1>{{ message }}</h1> </body> </html>
路由渲染模板
@app.get("/") async def read_root(request: Request): return templates.TemplateResponse( "index.html", { "request": request, # 必须包含 request 对象 "title": "首页", "message": "欢迎使用 FastAPI!" } )
高级模板功能
模板继承
templates/base.html:
<!DOCTYPE html> <html> <head> <title>{% block title %}{% endblock %}</title> {% block head %}{% endblock %} </head> <body> {% include "includes/header.html" %} {% block content %}{% endblock %} </body> </html> templates/page.html: {% extends "base.html" %} {% block title %}子页面{% endblock %} {% block content %} <h1>这是子页面内容</h1> {% endblock %}
循环和条件
<ul> {% for item in items %} <li {% if loop.first %}class="first"{% endif %}> {{ item.name }} - {{ item.price }} </li> {% endfor %} </ul> {% if user %} <p>欢迎回来,{{ user.username }}!</p> {% else %} <p>请先登录</p> {% endif %}
表单处理
模板 templates/form.html
<form method="post"> <input type="text" name="username" required> <input type="password" name="password" required> <button type="submit">登录</button> </form>
路由处理
from fastapi import Form @app.get("/login") async def login_form(request: Request): return templates.TemplateResponse("form.html", {"request": request}) @app.post("/login") async def do_login( username: str = Form(...), password: str = Form(...) ): # 验证逻辑 return {"username": username}
异步支持
FastAPI 支持在路由中异步渲染模板:
@app.get("/async-page") async def async_demo(request: Request): # 模拟异步操作(如数据库查询) data = await fetch_data_from_db() return templates.TemplateResponse("async.html", {"request": request, "data": data})
自定义过滤器
# 在模板引擎初始化后添加 def reverse_filter(s: str): return s[::-1] templates.env.filters["reverse"] = reverse_filter 模板中使用: <p>{{ "hello" | reverse }}</p> <!-- 输出 olleh -->
错误页面处理
from fastapi.exceptions import HTTPException @app.exception_handler(404) async def not_found_exception_handler(request: Request, exc: HTTPException): return templates.TemplateResponse( "404.html", {"request": request}, status_code=404 )
性能优化
- 模板缓存:Jinja2 默认启用缓存,生产环境无需额外配置。
- 静态文件 CDN:通过mount 托管静态文件,或使用 Nginx/CDN 加速。
- 异步渲染:对 I/O 密集型操作(如数据库查询)使用async/await 避免阻塞。
模板预加载
# 在应用启动时预编译模板 @app.on_event("startup") async def preload_templates(): templates.env.compile_templates( "templates", "compiled_templates.zip" )
异步渲染(需要第三方扩展)
# 使用 jinja2.asyncenv.AsyncEnvironment from jinja2 import FileSystemLoader from jinja2.asyncenv import AsyncEnvironment async_templates = AsyncEnvironment( loader=FileSystemLoader("templates"), enable_async=True ) @app.get("/async-page") async def async_page(request: Request): template = async_templates.get_template("async_page.html") content = await template.render_async(request=request) return HTMLResponse(content)
完整示例
from fastapi import FastAPI, Request, Form 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("/") async def home(request: Request): return templates.TemplateResponse( "index.html", { "request": request, "users": [ {"name": "Alice", "age": 30}, {"name": "Bob", "age": 25} ] } ) @app.get("/contact") async def contact(request: Request): return templates.TemplateResponse( "contact.html", {"request": request} ) @app.post("/submit-form") async def submit_form( name: str = Form(...), email: str = Form(...) ): return {"name": name, "email": email}
最佳实践
- 模板组织:
- 使用includes/ 目录存放可复用组件
- 通过html 实现模板继承
- 静态文件管理:
- 使用url_for(‘static’, path=’…’) 生成静态文件 URL
- 为 CSS/JS 添加版本号防止缓存
- 安全注意事项:
- 启用 Jinja2 自动转义:autoescape=True
- 避免直接渲染用户输入内容
- 开发热重载:
templates = Jinja2Templates( directory="templates", auto_reload=True # 开发环境启用 )
通过以上步骤,可以轻松在 FastAPI 中实现动态页面渲染。建议根据项目复杂度选择合适的功能组合,小型项目使用基础模板渲染即可,复杂项目可结合模板继承和自定义过滤器等功能。
局限性及替代方案
- 适用性:
- ✅ 适合简单页面或混合模式(API + 少量页面)。
- ❌ 复杂前端交互建议搭配前端框架(如 React/Vue)。
- 替代方案:
- 纯 API 模式:FastAPI 只提供数据,前端使用js/Nuxt.js 渲染。
- 全栈框架:若需更多内置功能(如 ORM、Admin 后台),可考虑 Django。
通过集成 Jinja2 模板引擎,FastAPI 可快速实现服务端渲染的网站开发,同时保留其异步高性能特性。适合轻量级全栈项目或需要 API 与页面混合交付的场景。对于复杂前端,建议采用前后端分离架构,用 FastAPI 专注提供 API 服务。