什么是模板
简单理解,模板就是 web
后端向前端发送的 html
模型
在前面的学习中,我们已经知道了关于 Fastapi 的请求和参数的使用方法。但是我们在实际的 web
开发中,都会以网页的形式展现。那么在 Fastapi 中我们也可以借助第三方的模板引擎来实现后端对网页模板的渲染
注:大家都知道目前 web 项目大都采用比较主流的前后端分离模式。但是为了学习方便,我们先采用后端渲染的方式
一、安装必要的依赖
首先,你需要安装 FastAPI 和模板引擎。这里我们使用 Jinja2,它是 Python 中最流行的模板引擎之一:
pip3 install fastapi uvicorn jinja2 python-multipart
如果你需要处理静态文件(如 CSS、JavaScript 或图片),还需要安装 python-multipart
二、配置模板引擎
1. 创建项目结构
推荐的项目结构如下:
project/
├── main.py
├── templates/
│ ├── base.html
│ ├── index.html
│ └── about.html
└── static/
├── css/
│ └── style.css
└── js/
└── script.js
2. 初始化模板引擎
下面是一个基本的 FastAPI 应用,配置了 Jinja2 模板引擎:
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 目录
templates = Jinja2Templates(directory="templates")
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
# 返回模板渲染后的 HTML
return templates.TemplateResponse("index.html", {"request": request, "title": "Home Page"})
三、创建基础模板
在 templates
目录下创建 base.html
文件,作为所有页面的基础模板:
<!-- templates/base.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}FastAPI App{% endblock %}</title>
<!-- 引入静态 CSS 文件 -->
<link rel="stylesheet" href="{{ url_for('static', path='/css/style.css') }}">
</head>
<body>
<header>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main>
{% block content %}
<!-- 子模板内容将在这里显示 -->
{% endblock %}
</main>
<footer>
<p>© 2025 FastAPI Tutorial</p>
</footer>
<!-- 引入静态 JS 文件 -->
<script src="{{ url_for('static', path='/js/script.js') }}"></script>
</body>
</html>
四、创建子模板
1. 首页模板 (index.html
)
<!-- templates/index.html -->
{% extends "base.html" %}
{% block title %} {{ title }} {% endblock %}
{% block content %}
<div class="container">
<h1>Welcome to FastAPI Template Tutorial</h1>
<p>Today's date: {{ current_date }}</p>
<h2>Users List</h2>
<ul>
{% for user in users %}
<li>{{ user.name }} ({{ user.email }})</li>
{% endfor %}
</ul>
<form action="/submit" method="post">
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
<button type="submit">Submit</button>
</form>
</div>
{% endblock %}
2. 关于页面模板 (about.html
)
<!-- templates/about.html -->
{% extends "base.html" %}
{% block title %} About Us {% endblock %}
{% block content %}
<div class="container">
<h1>About FastAPI Template Rendering</h1>
<p>This tutorial demonstrates how to use template rendering in FastAPI.</p>
</div>
{% endblock %}
五、处理模板变量和逻辑
修改 main.py
以传递更多数据到模板:
from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from datetime import datetime
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
# 模拟用户数据
users = [
{"name": "Alice", "email": "alice@example.com"},
{"name": "Bob", "email": "bob@example.com"},
{"name": "Charlie", "email": "charlie@example.com"}
]
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
return templates.TemplateResponse("index.html", {
"request": request,
"title": "Home Page",
"current_date": datetime.now().strftime("%Y-%m-%d"),
"users": users
})
@app.get("/about", response_class=HTMLResponse)
async def about(request: Request):
return templates.TemplateResponse("about.html", {"request": request})
@app.post("/submit", response_class=HTMLResponse)
async def submit(request: Request, name: str = Form(...)):
users.append({"name": name, "email": f"{name.lower()}@example.com"})
return templates.TemplateResponse("index.html", {
"request": request,
"title": "Home Page",
"current_date": datetime.now().strftime("%Y-%m-%d"),
"users": users,
"message": f"User {name} added successfully!"
})
六、模板中的高级功能
1. 条件语句
{% if message %}
<div class="alert success">
{{ message }}
</div>
{% endif %}
2. 循环
<ul>
{% for user in users %}
<li>{{ loop.index }}. {{ user.name }} ({{ user.email }})</li>
{% endfor %}
</ul>
3. 过滤器
<p>Uppercase: {{ "hello world" | upper }}</p>
<p>Truncated: {{ long_text | truncate(50) }}</p>
4. 自定义过滤器
在 main.py
中添加自定义过滤器:
# 注册自定义过滤器
def datetime_format(value, format="%Y-%m-%d %H:%M"):
return value.strftime(format)
templates.env.filters["datetime"] = datetime_format
在模板中使用:
<p>Formatted date: {{ current_date | datetime("%Y/%m/%d") }}</p>
七、静态文件处理
确保在 main.py
中正确挂载静态文件目录:
app.mount("/static", StaticFiles(directory="static"), name="static")
在模板中引用静态文件:
<link rel="stylesheet" href="{{ url_for('static', path='/css/style.css') }}">
<script src="{{ url_for('static', path='/js/script.js') }}"></script>
<img src="{{ url_for('static', path='/images/logo.png') }}" alt="Logo">
八、运行应用
使用以下命令启动 FastAPI 应用:
uvicorn main:app --reload
现在你可以访问 http://localhost:8000
查看渲染的页面
九、优化和扩展
1. 添加错误处理页面
@app.exception_handler(404)
async def not_found(request: Request, exc: Exception):
return templates.TemplateResponse("404.html", {"request": request}, status_code=404)
2. 使用布局和组件
创建可复用的组件,如导航栏、页脚等:
<!-- templates/components/navbar.html -->
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
在其他模板中导入:
{% include "components/navbar.html" %}