什么是模板

简单理解,模板就是 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>&copy; 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" %}
最后修改:2025 年 06 月 03 日
如果觉得我的文章对你有用,请随意赞赏